From 2786536d7f25b29b20a41b417896cff810368d85 Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Fri, 28 Dec 2001 03:08:27 +0000 Subject: When we clean, don't clean the model's last element. This helps keep 2001-12-27 Jon Trowbridge * gui/component/select-names/e-select-names.c (real_add_address_cb): When we clean, don't clean the model's last element. This helps keep things working properly when we have signal-character separators. (section_right_click_cb): Changed to work properly with our EText-emitted popup signal. (e_select_names_add_section): Use ETexts for the recipient sections, rather than tables. This lets us make them directly editable. (Bug #1721) * gui/component/select-names/e-select-names-popup.c (popup_info_new): Pass in a ESelectNamesTextModel, not a ESelectNamesModel. (e_select_names_popup): Adjust for the new signature for e_select_names_model_text_pos. * gui/component/select-names/e-select-names-manager.c (focus_out_cb): Schedule a cleaning when we focus out. (focus_in_cb): Cancel pending cleaning when we get focus. This helps us avoid bad things happening during the fast focus out/ins that happen when the completion dropdown appears. (completion_handler): Adjust for new signatures of e_select_names_model_text_pos and e_select_names_model_name_pos. (e_select_names_manager_entry_new): Pass in our ESelectNamesTextModel when constructing the ESelectNamesCompletion. (e_select_names_manager_entry_free): Cancel any pending clean-ups. * gui/component/select-names/e-select-names-bonobo.c (entry_get_property_fn): Get the text off of the text model. Which is the only way that really makes sense when you think about it. * gui/component/select-names/e-select-names-completion.c: Added a copy of the associated ESelectNamesTextModel to ESelectNamesCompletionPrivate. This replaces the ESelectNamesModel. (e_select_names_completion_destroy): Unref ->text_model. (e_select_names_completion_handle_request): Pass in our text model's separator info when calling e_select_names_model_text_pos. (e_select_names_completion_new): Pass in the text model as an arg instead of the model, and ref it as needed. * gui/component/select-names/e-select-names-text-model.c (e_select_names_text_model_init): Set separator as either ", " or ",", depending on the value of the EVOLUTION_DISABLE_MAGIC_COMMA environment variable. (e_select_names_text_model_destroy): Free the separator. (changed_cb): Flush our cached text on changed. (e_select_names_text_model_set_source): Use our own changed_cb callback on changed, rather than just connecting up e_text_model_changed. (e_select_names_text_model_set_separator): Added. Lets the separator between recipients be specified. (e_select_names_text_model_get_text): Cache the text we get from calling e_select_names_model_get_textification. (e_select_names_text_model_insert_length): A bunch of small changes to properly support generic separators, rather than (implicit and explicitly) assuming ", ". (e_select_names_text_model_delete): More small tweaks to handle generic separators. (e_select_names_text_model_get_nth_obj): Use new signature when calling e_select_names_model_name_pos, and use our cached text. * gui/component/select-names/e-select-names-model.c (e_select_names_model_destroy): We don't cache the text or addr_text anymore, so no need to free them here. (e_select_names_model_changed): ...and no need to reset our text and addr_text caches here. (e_select_names_model_get_textification): Take a separator as an arg, rather than just using ", ". Also, no caching. (e_select_names_model_get_address_text): Take a separator as an arg, rather than just using ", ". And no caching here either. (e_select_names_model_clean): Add arg that give us control over whether or not the last entry should get cleaned. We need this when using a one-character separator, so that new destinations that get tacked onto the end don't get immediately cleaned away for being empty. (e_select_names_model_name_pos): Take the separator length as an argument, remove implicit assumption of length 2. (e_select_names_model_text_pos): Take the separator length as an argument, remove implicit assumption of length 2.CVS: ---------------------------------------------------------------------- svn path=/trunk/; revision=15221 --- .../component/select-names/e-select-names-bonobo.c | 8 +- .../select-names/e-select-names-completion.c | 21 ++-- .../select-names/e-select-names-completion.h | 12 +- .../select-names/e-select-names-manager.c | 49 ++++++-- .../component/select-names/e-select-names-model.c | 140 ++++++++++----------- .../component/select-names/e-select-names-model.h | 10 +- .../component/select-names/e-select-names-popup.c | 31 ++--- .../component/select-names/e-select-names-popup.h | 4 +- .../select-names/e-select-names-text-model.c | 119 ++++++++++++------ .../select-names/e-select-names-text-model.h | 8 +- .../gui/component/select-names/e-select-names.c | 92 ++++++++------ 11 files changed, 291 insertions(+), 203 deletions(-) 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 55ef3ec89a..b2c791f259 100644 --- a/addressbook/gui/component/select-names/e-select-names-bonobo.c +++ b/addressbook/gui/component/select-names/e-select-names-bonobo.c @@ -75,11 +75,11 @@ entry_get_property_fn (BonoboPropertyBag *bag, switch (arg_id) { case ENTRY_PROPERTY_ID_TEXT: { - ESelectNamesModel *model; - model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (w), "select_names_model")); - g_assert (model != NULL); + ETextModel *text_model; + text_model = E_TEXT_MODEL (gtk_object_get_data (GTK_OBJECT (w), "select_names_text_model")); + g_assert (text_model != NULL); - BONOBO_ARG_SET_STRING (arg, e_select_names_model_get_textification (model)); + BONOBO_ARG_SET_STRING (arg, e_text_model_get_text (text_model)); break; } 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 eb15c4f232..cbfc1d56c6 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ b/addressbook/gui/component/select-names/e-select-names-completion.c @@ -55,7 +55,7 @@ typedef struct { struct _ESelectNamesCompletionPrivate { - ESelectNamesModel *model; + ESelectNamesTextModel *text_model; GList *book_data; gint books_not_ready; @@ -739,8 +739,8 @@ e_select_names_completion_destroy (GtkObject *object) ESelectNamesCompletion *comp = E_SELECT_NAMES_COMPLETION (object); GList *l; - if (comp->priv->model) - gtk_object_unref (GTK_OBJECT (comp->priv->model)); + if (comp->priv->text_model) + gtk_object_unref (GTK_OBJECT (comp->priv->text_model)); for (l = comp->priv->book_data; l; l = l->next) { ESelectNamesCompletionBookData *book_data = l->data; @@ -1142,8 +1142,10 @@ e_select_names_completion_handle_request (ECompletion *comp, const gchar *text, fprintf (out, "text=\"%s\" pos=%d limit=%d\n", text, pos, limit); } - e_select_names_model_text_pos (selcomp->priv->model, pos, &index, NULL, NULL); - str = index >= 0 ? e_select_names_model_get_string (selcomp->priv->model, index) : NULL; + e_select_names_model_text_pos (selcomp->priv->text_model->source, + selcomp->priv->text_model->seplen, + pos, &index, NULL, NULL); + str = index >= 0 ? e_select_names_model_get_string (selcomp->priv->text_model->source, index) : NULL; if (out) fprintf (out, "index=%d str=\"%s\"\n", index, str); @@ -1225,13 +1227,12 @@ e_select_names_completion_book_ready (EBook *book, EBookStatus status, ESelectNa */ ECompletion * -e_select_names_completion_new (EBook *book, ESelectNamesModel *model) +e_select_names_completion_new (EBook *book, ESelectNamesTextModel *text_model) { ESelectNamesCompletion *comp; g_return_val_if_fail (book == NULL || E_IS_BOOK (book), NULL); - g_return_val_if_fail (model, NULL); - g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); + g_return_val_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (text_model), NULL); comp = (ESelectNamesCompletion *) gtk_type_new (e_select_names_completion_get_type ()); @@ -1253,8 +1254,8 @@ e_select_names_completion_new (EBook *book, ESelectNamesModel *model) e_select_names_completion_add_book (comp, book); } - comp->priv->model = model; - gtk_object_ref (GTK_OBJECT (model)); + comp->priv->text_model = text_model; + gtk_object_ref (GTK_OBJECT (text_model)); return E_COMPLETION (comp); } diff --git a/addressbook/gui/component/select-names/e-select-names-completion.h b/addressbook/gui/component/select-names/e-select-names-completion.h index 03a30c3cc2..86522fa5ce 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.h +++ b/addressbook/gui/component/select-names/e-select-names-completion.h @@ -29,7 +29,7 @@ #include #include -#include "e-select-names-model.h" +#include "e-select-names-text-model.h" BEGIN_GNOME_DECLS @@ -54,12 +54,12 @@ struct _ESelectNamesCompletionClass { }; -GtkType e_select_names_completion_get_type (void); +GtkType e_select_names_completion_get_type (void); -ECompletion *e_select_names_completion_new (EBook *, ESelectNamesModel *); -void e_select_names_completion_add_book (ESelectNamesCompletion *, EBook *); -gboolean e_select_names_completion_get_match_contact_lists (ESelectNamesCompletion *); -void e_select_names_completion_set_match_contact_lists (ESelectNamesCompletion *, gboolean); +ECompletion *e_select_names_completion_new (EBook *, ESelectNamesTextModel *); +void e_select_names_completion_add_book (ESelectNamesCompletion *, EBook *); +gboolean e_select_names_completion_get_match_contact_lists (ESelectNamesCompletion *); +void e_select_names_completion_set_match_contact_lists (ESelectNamesCompletion *, gboolean); END_GNOME_DECLS 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 54d7344ece..53978ac502 100644 --- a/addressbook/gui/component/select-names/e-select-names-manager.c +++ b/addressbook/gui/component/select-names/e-select-names-manager.c @@ -51,6 +51,7 @@ typedef struct { EEntry *entry; ESelectNamesManager *manager; ESelectNamesModel *model; + guint cleaning_tag; } ESelectNamesManagerEntry; static void e_select_names_manager_init (ESelectNamesManager *manager); @@ -136,9 +137,24 @@ get_entry_info (EEntry *entry) static void popup_cb (EEntry *eentry, GdkEventButton *ev, gint pos, gpointer user_data) { - ESelectNamesManagerEntry *entry = user_data; + ESelectNamesTextModel *text_model; + + gtk_object_get (GTK_OBJECT (eentry), + "model", &text_model, + NULL); + g_assert (E_IS_SELECT_NAMES_TEXT_MODEL (text_model)); + + e_select_names_popup (text_model, ev, pos); +} - e_select_names_popup (entry->model, ev, pos); +static gboolean +clean_cb (gpointer ptr) +{ + ESelectNamesManagerEntry *entry = ptr; + + e_select_names_model_clean (entry->model, TRUE); + entry->cleaning_tag = 0; + return FALSE; } static gint @@ -146,6 +162,11 @@ focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) { ESelectNamesManagerEntry *entry = user_data; + if (entry->cleaning_tag) { + gtk_timeout_remove (entry->cleaning_tag); + entry->cleaning_tag = 0; + } + e_select_names_model_cancel_cardify_all (entry->model); return FALSE; @@ -155,11 +176,13 @@ static gint focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) { ESelectNamesManagerEntry *entry = user_data; + gboolean visible = e_entry_completion_popup_is_visible (entry->entry); - e_select_names_model_clean (entry->model); - - if (!e_entry_completion_popup_is_visible (entry->entry)) + if (! visible) { e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 100); + if (entry->cleaning_tag == 0) + entry->cleaning_tag = gtk_timeout_add (100, clean_cb, entry); + } return FALSE; } @@ -177,6 +200,7 @@ static void completion_handler (EEntry *entry, ECompletionMatch *match) { ESelectNamesManagerEntry *mgr_entry; + ESelectNamesTextModel *text_model; EDestination *dest; gint i, pos, start_pos, len; @@ -191,10 +215,15 @@ completion_handler (EEntry *entry, ECompletionMatch *match) bitch. */ gtk_object_ref (GTK_OBJECT (dest)); + gtk_object_get (GTK_OBJECT (entry), + "model", &text_model, + NULL); + g_assert (E_IS_SELECT_NAMES_TEXT_MODEL (text_model)); + pos = e_entry_get_position (entry); - e_select_names_model_text_pos (mgr_entry->model, pos, &i, NULL, NULL); + e_select_names_model_text_pos (mgr_entry->model, text_model->seplen, pos, &i, NULL, NULL); e_select_names_model_replace (mgr_entry->model, i, dest); - e_select_names_model_name_pos (mgr_entry->model, i, &start_pos, &len); + e_select_names_model_name_pos (mgr_entry->model, text_model->seplen, i, &start_pos, &len); e_entry_set_position (entry, start_pos+len); } @@ -223,7 +252,7 @@ e_select_names_manager_entry_new (ESelectNamesManager *manager, ESelectNamesMode gtk_object_ref (GTK_OBJECT (entry->entry)); - comp = e_select_names_completion_new (NULL, model); + comp = e_select_names_completion_new (NULL, E_SELECT_NAMES_TEXT_MODEL (text_model)); if (manager->completion_book) e_select_names_completion_add_book (E_SELECT_NAMES_COMPLETION (comp), manager->completion_book); @@ -257,6 +286,7 @@ e_select_names_manager_entry_new (ESelectNamesManager *manager, ESelectNamesMode gtk_object_set_data (GTK_OBJECT (entry->entry), "entry_info", entry); gtk_object_set_data (GTK_OBJECT (entry->entry), "select_names_model", model); + gtk_object_set_data (GTK_OBJECT (entry->entry), "select_names_text_model", text_model); gtk_object_set_data (GTK_OBJECT (entry->entry), "completion_handler", comp); return entry; @@ -272,6 +302,9 @@ e_select_names_manager_entry_free (ESelectNamesManagerEntry *entry) gtk_object_unref (GTK_OBJECT (entry->model)); gtk_object_unref (GTK_OBJECT (entry->entry)); + if (entry->cleaning_tag) + gtk_timeout_remove (entry->cleaning_tag); + g_free (entry); } 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 138b0d73ad..fadb8c21a0 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.c +++ b/addressbook/gui/component/select-names/e-select-names-model.c @@ -20,9 +20,6 @@ #include "e-select-names-model.h" #include "addressbook/backend/ebook/e-card-simple.h" -#define SEPARATOR ", " -#define SEPLEN (strlen(SEPARATOR)) - #define MAX_LENGTH 2047 @@ -56,8 +53,6 @@ struct _ESelectNamesModelPrivate { gchar *title; GList *data; /* of EDestination */ - gchar *text; - gchar *addr_text; gint limit; @@ -170,9 +165,6 @@ e_select_names_model_destroy (GtkObject *object) g_list_foreach (model->priv->data, (GFunc) gtk_object_unref, NULL); g_list_free (model->priv->data); - g_free (model->priv->text); - g_free (model->priv->addr_text); - g_free (model->priv); } @@ -215,12 +207,6 @@ e_select_names_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) static void e_select_names_model_changed (ESelectNamesModel *model) { - g_free (model->priv->text); - model->priv->text = NULL; - - g_free (model->priv->addr_text); - model->priv->addr_text = NULL; - if (model->priv->freeze_count > 0) { model->priv->pending_changed = TRUE; } else { @@ -264,76 +250,78 @@ e_select_names_model_duplicate (ESelectNamesModel *old) return model; } -const gchar * -e_select_names_model_get_textification (ESelectNamesModel *model) +gchar * +e_select_names_model_get_textification (ESelectNamesModel *model, const char *separator) { + gchar *text; + g_return_val_if_fail (model != NULL, NULL); g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); + g_return_val_if_fail (separator && *separator, NULL); - if (model->priv->text == NULL) { - - if (model->priv->data == NULL) { - - model->priv->text = g_strdup (""); - - } else { - gchar **strv = g_new0 (gchar *, g_list_length (model->priv->data)+1); - gint i = 0; - GList *iter = model->priv->data; - - while (iter) { - EDestination *dest = E_DESTINATION (iter->data); - strv[i] = (gchar *) e_destination_get_textrep (dest); - ++i; - iter = g_list_next (iter); - } - - model->priv->text = g_strjoinv (SEPARATOR, strv); + if (model->priv->data == NULL) { + + text = g_strdup (""); - if (strlen(model->priv->text) > MAX_LENGTH) { - model->priv->text[MAX_LENGTH] = 0; - g_realloc (model->priv->text, MAX_LENGTH + 1); - } - - g_free (strv); + } else { + gchar **strv = g_new0 (gchar *, g_list_length (model->priv->data)+1); + gint i = 0; + GList *iter = model->priv->data; + + while (iter) { + EDestination *dest = E_DESTINATION (iter->data); + strv[i] = (gchar *) e_destination_get_textrep (dest); + ++i; + iter = g_list_next (iter); + } + + text = g_strjoinv (separator, strv); + + if (strlen(text) > MAX_LENGTH) { + text[MAX_LENGTH] = '\0'; + text = g_realloc (text, MAX_LENGTH + 1); } + + g_free (strv); + } - return model->priv->text; + return text; } -const gchar * -e_select_names_model_get_address_text (ESelectNamesModel *model) +gchar * +e_select_names_model_get_address_text (ESelectNamesModel *model, const char *separator) { + gchar *addr_text; + g_return_val_if_fail (model != NULL, NULL); g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); + g_return_val_if_fail (separator && *separator, NULL); - if (model->priv->addr_text == NULL) { - - if (model->priv->data == NULL) { - - model->priv->addr_text = g_strdup (""); - - } else { - gchar **strv = g_new0 (gchar *, g_list_length (model->priv->data)+1); - gint i = 0; - GList *iter = model->priv->data; - - while (iter) { - EDestination *dest = E_DESTINATION (iter->data); - strv[i] = (gchar *) e_destination_get_address (dest); - if (strv[i]) - ++i; - iter = g_list_next (iter); - } - - model->priv->addr_text = g_strjoinv (SEPARATOR, strv); + if (model->priv->data == NULL) { - g_free (strv); + addr_text = g_strdup (""); + + } else { + gchar **strv = g_new0 (gchar *, g_list_length (model->priv->data)+1); + gint i = 0; + GList *iter = model->priv->data; + + while (iter) { + EDestination *dest = E_DESTINATION (iter->data); + strv[i] = (gchar *) e_destination_get_address (dest); + if (strv[i]) + ++i; + iter = g_list_next (iter); } + + addr_text = g_strjoinv (separator, strv); + + g_free (strv); + } - return model->priv->addr_text; + return addr_text; } gint @@ -614,7 +602,7 @@ e_select_names_model_delete (ESelectNamesModel *model, gint index) } void -e_select_names_model_clean (ESelectNamesModel *model) +e_select_names_model_clean (ESelectNamesModel *model, gboolean clean_last_entry) { GList *iter, *next; gboolean changed = FALSE; @@ -627,6 +615,10 @@ e_select_names_model_clean (ESelectNamesModel *model) EDestination *dest; next = g_list_next (iter); + + if (next == NULL && !clean_last_entry) + break; + dest = iter->data ? E_DESTINATION (iter->data) : NULL; if (dest == NULL || e_destination_is_empty (dest)) { @@ -705,19 +697,19 @@ e_select_names_model_merge (ESelectNamesModel *dest, ESelectNamesModel *src) } void -e_select_names_model_name_pos (ESelectNamesModel *model, gint index, gint *pos, gint *length) +e_select_names_model_name_pos (ESelectNamesModel *model, gint seplen, gint index, gint *pos, gint *length) { gint rp = 0, i, len = 0; GList *iter; const gchar *str; - g_return_if_fail (model != NULL); g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); + g_return_if_fail (seplen > 0); i = 0; iter = model->priv->data; while (iter && i <= index) { - rp += len + (i > 0 ? SEPLEN : 0); + rp += len + (i > 0 ? seplen : 0); str = e_destination_get_textrep (E_DESTINATION (iter->data)); len = str ? strlen (str) : 0; ++i; @@ -736,14 +728,14 @@ e_select_names_model_name_pos (ESelectNamesModel *model, gint index, gint *pos, } void -e_select_names_model_text_pos (ESelectNamesModel *model, gint pos, gint *index, gint *start_pos, gint *length) +e_select_names_model_text_pos (ESelectNamesModel *model, gint seplen, gint pos, gint *index, gint *start_pos, gint *length) { GList *iter; const gchar *str; gint len = 0, i = 0, sp = 0, adj = 0; - g_return_if_fail (model != NULL); g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model)); + g_return_if_fail (seplen > 0); iter = model->priv->data; @@ -756,14 +748,14 @@ e_select_names_model_text_pos (ESelectNamesModel *model, gint pos, gint *index, } sp += len + adj + 1; - adj = 1; + adj = seplen-1; ++i; iter = g_list_next (iter); } if (i != 0) - ++sp; /* skip past "magic space" */ + sp += seplen-1; /* skip past "magic space" */ if (iter == NULL) { #if 0 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 b7fa04d6cd..9179eb676d 100644 --- a/addressbook/gui/component/select-names/e-select-names-model.h +++ b/addressbook/gui/component/select-names/e-select-names-model.h @@ -46,8 +46,8 @@ GtkType e_select_names_model_get_type (void); ESelectNamesModel *e_select_names_model_new (void); ESelectNamesModel *e_select_names_model_duplicate (ESelectNamesModel *old); -const gchar *e_select_names_model_get_textification (ESelectNamesModel *model); -const gchar *e_select_names_model_get_address_text (ESelectNamesModel *model); +gchar *e_select_names_model_get_textification (ESelectNamesModel *model, const char *separator); +gchar *e_select_names_model_get_address_text (ESelectNamesModel *model, const char *separator); gint e_select_names_model_count (ESelectNamesModel *model); gint e_select_names_model_get_limit (ESelectNamesModel *model); @@ -71,10 +71,10 @@ void e_select_names_model_delete_all (ESelectNamesModel *model); void e_select_names_model_overwrite_copy (ESelectNamesModel *dest, ESelectNamesModel *src); void e_select_names_model_merge (ESelectNamesModel *dest, ESelectNamesModel *src); -void e_select_names_model_clean (ESelectNamesModel *model); +void e_select_names_model_clean (ESelectNamesModel *model, gboolean clean_last_entry); -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_name_pos (ESelectNamesModel *model, gint seplen, gint index, gint *pos, gint *length); +void e_select_names_model_text_pos (ESelectNamesModel *model, gint seplen, gint pos, gint *index, gint *start_pos, gint *length); void e_select_names_model_cardify (ESelectNamesModel *model, EBook *book, gint index, gint delay); gboolean e_select_names_model_uncardify (ESelectNamesModel *model, gint index); 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 a6e6bdea8e..442a00b6c1 100644 --- a/addressbook/gui/component/select-names/e-select-names-popup.c +++ b/addressbook/gui/component/select-names/e-select-names-popup.c @@ -46,23 +46,23 @@ typedef struct _PopupInfo PopupInfo; struct _PopupInfo { - ESelectNamesModel *model; + ESelectNamesTextModel *text_model; const EDestination *dest; gint pos; gint index; }; static PopupInfo * -popup_info_new (ESelectNamesModel *model, const EDestination *dest, gint pos, gint index) +popup_info_new (ESelectNamesTextModel *text_model, const EDestination *dest, gint pos, gint index) { PopupInfo *info = g_new0 (PopupInfo, 1); - info->model = model; + info->text_model = text_model; info->dest = dest; info->pos = pos; info->index = index; - if (model) - gtk_object_ref (GTK_OBJECT (model)); + if (text_model) + gtk_object_ref (GTK_OBJECT (text_model)); if (dest) gtk_object_ref (GTK_OBJECT (dest)); @@ -75,8 +75,8 @@ popup_info_free (PopupInfo *info) { if (info) { - if (info->model) - gtk_object_unref (GTK_OBJECT (info->model)); + if (info->text_model) + gtk_object_unref (GTK_OBJECT (info->text_model)); if (info->dest) gtk_object_unref (GTK_OBJECT (info->dest)); @@ -144,7 +144,7 @@ change_email_num_cb (GtkWidget *w, gpointer user_data) if (n != e_destination_get_email_num (info->dest)) { dest = e_destination_new (); e_destination_set_card (dest, e_destination_get_card (info->dest), n); - e_select_names_model_replace (info->model, info->index, dest); + e_select_names_model_replace (info->text_model->source, info->index, dest); } } @@ -153,7 +153,7 @@ static void remove_recipient_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; - e_select_names_model_delete (info->model, info->index); + e_select_names_model_delete (info->text_model->source, info->index); } static void @@ -168,7 +168,7 @@ static void remove_all_recipients_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; - e_select_names_model_delete_all (info->model); + e_select_names_model_delete_all (info->text_model->source); } static void @@ -511,19 +511,22 @@ popup_menu_nocard (PopupInfo *info) } void -e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) +e_select_names_popup (ESelectNamesTextModel *text_model, GdkEventButton *ev, gint pos) { + ESelectNamesModel *model; GtkWidget *popup; PopupInfo *info; const EDestination *dest; ECard *card; gint index; - g_return_if_fail (model && E_IS_SELECT_NAMES_MODEL (model)); + g_return_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (text_model)); g_return_if_fail (ev); g_return_if_fail (0 <= pos); - e_select_names_model_text_pos (model, pos, &index, NULL, NULL); + model = text_model->source; + + e_select_names_model_text_pos (model, text_model->seplen, pos, &index, NULL, NULL); if (index < 0 || index >= e_select_names_model_count (model)) return; @@ -533,7 +536,7 @@ e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) card = e_destination_get_card (dest); - info = popup_info_new (model, dest, pos, index); + info = popup_info_new (text_model, dest, pos, index); if (e_destination_contains_card (dest)) { if (e_destination_is_evolution_list (dest)) diff --git a/addressbook/gui/component/select-names/e-select-names-popup.h b/addressbook/gui/component/select-names/e-select-names-popup.h index 5a4685f8cb..09cd29da18 100644 --- a/addressbook/gui/component/select-names/e-select-names-popup.h +++ b/addressbook/gui/component/select-names/e-select-names-popup.h @@ -27,9 +27,9 @@ #ifndef __E_SELECT_NAMES_POPUP_H__ #define __E_SELECT_NAMES_POPUP_H__ -#include "e-select-names-model.h" +#include "e-select-names-text-model.h" -void e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos); +void e_select_names_popup (ESelectNamesTextModel *text_model, GdkEventButton *ev, gint pos); #endif /* __E_SELECT_NAMES_POPUP_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 d2e77d6316..8faa99d0e4 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 @@ -22,8 +22,6 @@ static FILE *out = NULL; /* stream for debugging spew */ -#define SEPLEN 2 - /* Object argument IDs */ enum { ARG_0, @@ -140,7 +138,16 @@ dump_model (ESelectNamesTextModel *text_model) static void e_select_names_text_model_init (ESelectNamesTextModel *model) { + const gchar *default_sep; + model->last_magic_comma_pos = -1; + + if (getenv ("EVOLUTION_DISABLE_MAGIC_COMMA")) + default_sep = ","; + else + default_sep = ", "; + + e_select_names_text_model_set_separator (model, default_sep); } static void @@ -149,6 +156,9 @@ e_select_names_text_model_destroy (GtkObject *object) ESelectNamesTextModel *model; model = E_SELECT_NAMES_TEXT_MODEL (object); + + g_free (model->text); + g_free (model->sep); e_select_names_text_model_set_source (model, NULL); @@ -195,8 +205,9 @@ resize_cb (ESelectNamesModel *source, gint index, gint old_len, gint new_len, ET EReposDeleteShift repos_del; EReposInsertShift repos_ins; gint pos; + gint seplen = E_SELECT_NAMES_TEXT_MODEL (model)->seplen; - e_select_names_model_name_pos (source, index, &pos, NULL); + e_select_names_model_name_pos (source, seplen, index, &pos, NULL); if (new_len < old_len) { @@ -215,6 +226,17 @@ resize_cb (ESelectNamesModel *source, gint index, gint old_len, gint new_len, ET } } +static void +changed_cb (ETextModel *model) +{ + ESelectNamesTextModel *text_model = E_SELECT_NAMES_TEXT_MODEL (model); + + g_free (text_model->text); + text_model->text = NULL; + + e_text_model_changed (model); +} + static void e_select_names_text_model_set_source (ESelectNamesTextModel *model, @@ -235,7 +257,7 @@ e_select_names_text_model_set_source (ESelectNamesTextModel *model, gtk_object_ref (GTK_OBJECT (model->source)); model->source_changed_id = gtk_signal_connect_object (GTK_OBJECT(model->source), "changed", - GTK_SIGNAL_FUNC (e_text_model_changed), + GTK_SIGNAL_FUNC (changed_cb), GTK_OBJECT (model)); model->source_resize_id = gtk_signal_connect (GTK_OBJECT(model->source), "resized", @@ -252,12 +274,28 @@ e_select_names_text_model_new (ESelectNamesModel *source) return model; } +void +e_select_names_text_model_set_separator (ESelectNamesTextModel *model, const char *sep) +{ + g_return_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (model)); + g_return_if_fail (sep && *sep); + + g_free (model->sep); + model->sep = g_strdup (sep); + model->seplen = strlen (sep); +} + static const gchar * e_select_names_text_model_get_text (ETextModel *model) { ESelectNamesTextModel *snm = E_SELECT_NAMES_TEXT_MODEL(model); - return snm ? e_select_names_model_get_textification (snm->source) : ""; + if (snm == NULL) + return ""; + else if (snm->text == NULL) + snm->text = e_select_names_model_get_textification (snm->source, snm->sep); + + return snm->text; } static void @@ -278,11 +316,10 @@ e_select_names_text_model_insert (ETextModel *model, gint position, const gchar static void e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gchar *text, gint length) { - ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source; - gint i; + ESelectNamesTextModel *text_model = E_SELECT_NAMES_TEXT_MODEL (model); + ESelectNamesModel *source = text_model->source; - g_return_if_fail (model != NULL); - g_return_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (model)); + gint i; if (out) { gchar *tmp = g_strndup (text, length); @@ -290,11 +327,11 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha g_free (tmp); } - pos = CLAMP (pos, 0, strlen (e_select_names_model_get_textification (source))); + pos = CLAMP (pos, 0, strlen (e_select_names_model_get_textification (source, text_model->sep))); /* We want to control all cursor motions ourselves, rather than taking hints from the ESelectNamesModel. */ - gtk_signal_handler_block (GTK_OBJECT (source), E_SELECT_NAMES_TEXT_MODEL (model)->source_resize_id); + gtk_signal_handler_block (GTK_OBJECT (source), text_model->source_resize_id); /* We handle this one character at a time. */ @@ -302,17 +339,17 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha gint index, start_pos, text_len; gboolean inside_quote = FALSE; - E_SELECT_NAMES_TEXT_MODEL (model)->last_magic_comma_pos = -1; + text_model->last_magic_comma_pos = -1; if (out) fprintf (out, "processing [%c]\n", text[i]); - e_select_names_model_text_pos (source, pos, &index, &start_pos, &text_len); + e_select_names_model_text_pos (source, text_model->seplen, pos, &index, &start_pos, &text_len); 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? */ + if (text[i] == *text_model->sep && index >= 0) { /* Is this a quoted or an unquoted separator we are dealing with? */ const EDestination *dest = e_select_names_model_get_destination (source, index); if (dest) { const gchar *str = e_destination_get_textrep (dest); @@ -331,7 +368,7 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha } - if (text[i] == ',' && !inside_quote) { + if (text[i] == *text_model->sep && !inside_quote) { /* This is the case of hitting , first thing in an empty entry */ if (index == -1) { @@ -361,9 +398,9 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha repos.model = model; repos.pos = pos; - repos.len = SEPLEN; + repos.len = text_model->seplen; e_text_model_reposition (model, e_repos_insert_shift, &repos); - pos += SEPLEN; + pos += text_model->seplen; } } else { @@ -385,12 +422,13 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha repos.model = model; repos.pos = pos; - repos.len = SEPLEN; + repos.len = text_model->seplen; e_text_model_reposition (model, e_repos_insert_shift, &repos); - pos += SEPLEN; + pos += text_model->seplen; } - E_SELECT_NAMES_TEXT_MODEL (model)->last_magic_comma_pos = pos; + if (text_model->seplen > 1) + text_model->last_magic_comma_pos = pos; } else { EReposInsertShift repos; @@ -408,6 +446,7 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha this_length = 0; } else { /* Adjust for our "magic white space" */ + /* FIXME: This code does the wrong thing if seplen > 2 */ new_str = g_strdup_printf("%c%s%s", text[i], pos < start_pos ? " " : "", str); if (pos < start_pos) ++this_length; @@ -447,20 +486,21 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha } } - dump_model (E_SELECT_NAMES_TEXT_MODEL (model)); + dump_model (text_model); - gtk_signal_handler_unblock (GTK_OBJECT (source), E_SELECT_NAMES_TEXT_MODEL (model)->source_resize_id); + gtk_signal_handler_unblock (GTK_OBJECT (source), text_model->source_resize_id); } static void e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) { - ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source; + ESelectNamesTextModel *text_model = E_SELECT_NAMES_TEXT_MODEL (model); + ESelectNamesModel *source = text_model->source; gint index, start_pos, text_len, offset; if (out) { - const gchar *str = e_select_names_model_get_textification (source); + const gchar *str = e_select_names_model_get_textification (source, text_model->sep); gint i, len; fprintf (out, ">> delete %d at pos %d\n", length, pos); @@ -480,15 +520,14 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) if (length < 0) return; - if (E_SELECT_NAMES_TEXT_MODEL (model)->last_magic_comma_pos == pos+1 - && length == 1) { - --pos; + if (text_model->last_magic_comma_pos == pos+1 && length == 1) { + pos -= text_model->seplen-1; if (pos >= 0) - ++length; - E_SELECT_NAMES_TEXT_MODEL (model)->last_magic_comma_pos = -1; + length = text_model->seplen; + text_model->last_magic_comma_pos = -1; } - e_select_names_model_text_pos (source, pos, &index, &start_pos, &text_len); + e_select_names_model_text_pos (source, text_model->seplen, pos, &index, &start_pos, &text_len); if (out) fprintf (out, "index=%d, start_pos=%d, text_len=%d\n", index, start_pos, text_len); @@ -529,7 +568,7 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) ++str2; if (str1 && str2) - new_str = g_strdup_printf ("%s %s", str1, str2); + new_str = g_strdup_printf ("%s%s%s", str1, text_model->sep+1, str2); else if (str1) new_str = g_strdup (str1); else if (str2) @@ -549,7 +588,7 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) repos.model = model; repos.pos = pos; - repos.len = SEPLEN - 1; + repos.len = text_model->seplen; e_text_model_reposition (model, e_repos_delete_shift, &repos); @@ -577,11 +616,11 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) repos.model = model; repos.pos = pos; - repos.len = text_len + SEPLEN; + repos.len = text_len + text_model->seplen; e_text_model_reposition (model, e_repos_delete_shift, &repos); - length -= text_len + SEPLEN; + length -= text_len + text_model->seplen; if (length > 0) e_select_names_text_model_delete (model, pos, length); @@ -644,7 +683,7 @@ e_select_names_text_model_delete (ETextModel *model, gint pos, gint length) repos.model = model; repos.pos = pos; - repos.len = SEPLEN; + repos.len = text_model->seplen; e_text_model_reposition (model, e_repos_delete_shift, &repos); } @@ -700,7 +739,8 @@ nth_obj_index (ESelectNamesModel *source, gint n) static const gchar * e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len) { - ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source; + ESelectNamesTextModel *text_model = E_SELECT_NAMES_TEXT_MODEL (model); + ESelectNamesModel *source = text_model->source; const gchar *txt; gint i, pos; @@ -708,12 +748,13 @@ e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len) if (i < 0) return NULL; - e_select_names_model_name_pos (source, i, &pos, len); + e_select_names_model_name_pos (source, text_model->seplen, i, &pos, len); if (pos < 0) return NULL; - txt = e_select_names_model_get_textification (source); - return txt + pos; + if (text_model->text == NULL) + text_model->text = e_select_names_model_get_textification (source, text_model->sep); + return text_model->text + pos; } static void diff --git a/addressbook/gui/component/select-names/e-select-names-text-model.h b/addressbook/gui/component/select-names/e-select-names-text-model.h index fa6ab11a63..29ab727368 100644 --- a/addressbook/gui/component/select-names/e-select-names-text-model.h +++ b/addressbook/gui/component/select-names/e-select-names-text-model.h @@ -32,6 +32,11 @@ struct _ESelectNamesTextModel { gint source_changed_id; gint source_resize_id; + gchar *text; + + gchar *sep; + gint seplen; + gint last_magic_comma_pos; }; @@ -39,7 +44,8 @@ struct _ESelectNamesTextModelClass { ETextModelClass parent_class; }; -ETextModel *e_select_names_text_model_new (ESelectNamesModel *source); +ETextModel *e_select_names_text_model_new (ESelectNamesModel *source); +void e_select_names_text_model_set_separator (ESelectNamesTextModel *model, const char *sep); /* Standard Gtk function */ GtkType e_select_names_text_model_get_type (void); diff --git a/addressbook/gui/component/select-names/e-select-names.c b/addressbook/gui/component/select-names/e-select-names.c index 1ee8d345a4..095d928a41 100644 --- a/addressbook/gui/component/select-names/e-select-names.c +++ b/addressbook/gui/component/select-names/e-select-names.c @@ -42,7 +42,7 @@ #include "e-select-names.h" #include -#include "e-select-names-table-model.h" +#include "e-select-names-text-model.h" #include #include #include @@ -63,11 +63,12 @@ enum { }; typedef struct { - char *title; - ETableModel *model; - ESelectNamesModel *source; - ESelectNames *names; - GtkWidget *label; + char *title; + ETableModel *model; + ESelectNamesModel *source; + ESelectNamesTextModel *text_model; + ESelectNames *names; + GtkWidget *label; } ESelectNamesChild; GtkType @@ -215,7 +216,7 @@ real_add_address_cb (int model_row, gpointer closure) e_destination_set_card (dest, card, 0); e_select_names_model_append (child->source, dest); - e_select_names_model_clean (child->source); + e_select_names_model_clean (child->source, FALSE); gtk_object_unref(GTK_OBJECT(card)); } @@ -513,10 +514,11 @@ add_additional_select_names_uris (ESelectNames *e_select_names, CORBA_Environmen Bonobo_ConfigDatabase config_db; guint32 num_additional_uris; int i; + gboolean flag; config_db = addressbook_config_database (ev); - num_additional_uris = bonobo_config_get_ulong_with_default (config_db, "/Addressbook/additional_select_names_folders/num", 0, ev); + num_additional_uris = bonobo_config_get_ulong_with_default (config_db, "/Addressbook/additional_select_names_folders/num", 0, &flag); for (i = 0; i < num_additional_uris; i ++) { ESelectNamesFolder *e_folder; char *config_path; @@ -775,18 +777,21 @@ button_clicked(GtkWidget *button, ESelectNamesChild *child) real_add_address(child->names, child); } +#if 0 static void remove_address(ETable *table, int row, int col, GdkEvent *event, ESelectNamesChild *child) { e_select_names_model_delete (child->source, row); } +#endif struct _RightClickData { - ETable *table; ESelectNamesChild *child; + int index; }; typedef struct _RightClickData RightClickData; +#if 0 static GSList *selected_rows = NULL; static void @@ -805,47 +810,38 @@ selected_rows_foreach_cb (void *row, void *data) remove_address (NULL, GPOINTER_TO_INT (row), 0, NULL, child); } +#endif static void remove_cb (GtkWidget *widget, void *data) { RightClickData *rcdata = (RightClickData *)data; - e_select_names_model_freeze (rcdata->child->source); - - /* Build a list of selected rows */ - e_table_selected_row_foreach (rcdata->table, - etable_selection_foreach_cb, - rcdata->child); - - /* Now process the list we made, removing each selected row */ - g_slist_foreach (selected_rows, - (GFunc)selected_rows_foreach_cb, - rcdata->child); - - e_select_names_model_thaw (rcdata->child->source); + e_select_names_model_delete (rcdata->child->source, rcdata->index); /* Free everything we've created */ g_free (rcdata); - g_slist_free (selected_rows); - selected_rows = NULL; } static void -section_right_click_cb (ETable *table, gint row, gint col, GdkEvent *event, ESelectNamesChild *child) +section_right_click_cb (EText *text, GdkEventButton *ev, gint pos, ESelectNamesChild *child) { EPopupMenu right_click_menu[] = { { N_("Remove"), NULL, GTK_SIGNAL_FUNC (remove_cb), NULL, 0 }, { NULL, NULL, NULL, 0 } }; + gint index; + + e_select_names_model_text_pos (child->source, child->text_model->seplen, pos, &index, NULL, NULL); - RightClickData *rcdata = g_new0 (RightClickData, 1); - rcdata->table = table; - rcdata->child = child; + if (index != -1) { + RightClickData *rcdata = g_new0 (RightClickData, 1); + rcdata->index = index; + rcdata->child = child; - e_popup_menu_run (right_click_menu, event, 0, 0, - rcdata); + e_popup_menu_run (right_click_menu, (GdkEvent *)ev, 0, 0, rcdata); + } } void @@ -858,8 +854,8 @@ e_select_names_add_section(ESelectNames *e_select_names, char *name, char *id, E GtkTable *table; char *label_text; - ETableModel *model; - GtkWidget *etable; + GtkWidget *sw; + GtkWidget *recipient_table; if (g_hash_table_lookup(e_select_names->children, id)) { return; @@ -872,6 +868,12 @@ e_select_names_add_section(ESelectNames *e_select_names, char *name, char *id, E child->names = e_select_names; child->title = e_utf8_from_locale_string(_(name)); + child->text_model = (ESelectNamesTextModel *) e_select_names_text_model_new (source); + e_select_names_text_model_set_separator (child->text_model, "\n"); + + child->source = source; + gtk_object_ref(GTK_OBJECT(child->source)); + e_select_names->child_count++; alignment = gtk_alignment_new(0, 0, 1, 0); @@ -909,27 +911,37 @@ e_select_names_add_section(ESelectNames *e_select_names, char *name, char *id, E GTK_FILL, GTK_FILL, 0, 0); - model = e_select_names_table_model_new(source); - etable = e_table_scrolled_new (model, NULL, SPEC2, NULL); + + sw = gtk_scrolled_window_new (NULL, NULL); + recipient_table = e_entry_new (); + gtk_object_set (GTK_OBJECT (recipient_table), + "model", child->text_model, + "allow_newlines", TRUE, + NULL); + + gtk_signal_connect (GTK_OBJECT (recipient_table), + "popup", + GTK_SIGNAL_FUNC (section_right_click_cb), + child); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), recipient_table); + +#if 0 gtk_signal_connect(GTK_OBJECT(e_table_scrolled_get_table(E_TABLE_SCROLLED(etable))), "right_click", GTK_SIGNAL_FUNC(section_right_click_cb), child); gtk_signal_connect(GTK_OBJECT(e_table_scrolled_get_table(E_TABLE_SCROLLED(etable))), "double_click", GTK_SIGNAL_FUNC(remove_address), child); +#endif - child->model = model; - child->source = source; - gtk_object_ref(GTK_OBJECT(child->model)); - gtk_object_ref(GTK_OBJECT(child->source)); gtk_signal_connect (GTK_OBJECT (child->source), "changed", GTK_SIGNAL_FUNC (sync_table_and_models), e_select_names); - gtk_widget_show(etable); + gtk_widget_show_all (sw); - gtk_table_attach(table, etable, + gtk_table_attach(table, sw, 1, 2, e_select_names->child_count, e_select_names->child_count + 1, -- cgit v1.2.3