aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/gui/component/select-names/e-select-names-text-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'addressbook/gui/component/select-names/e-select-names-text-model.c')
-rw-r--r--addressbook/gui/component/select-names/e-select-names-text-model.c797
1 files changed, 527 insertions, 270 deletions
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 13054eb10e..62e1676d20 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
@@ -1,45 +1,51 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors:
- * Chris Lahey <clahey@helixcode.com>
+ * Chris Lahey <clahey@ximian.com>
+ * Jon Trowbridge <trow@ximian.com>
*
- * Copyright (C) 2000 Helix Code, Inc.
+ * Copyright (C) 2000, 2001 Ximian, Inc.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <gtk/gtk.h>
+#include <gal/e-text/e-text-model-repos.h>
#include <addressbook/contact-editor/e-contact-editor.h>
#include "e-select-names-text-model.h"
+static FILE *out = NULL; /* stream for debugging spew */
+
+#define SEPLEN 2
+
/* Object argument IDs */
enum {
ARG_0,
ARG_SOURCE,
};
-static void e_select_names_text_model_init (ESelectNamesTextModel *model);
static void e_select_names_text_model_class_init (ESelectNamesTextModelClass *klass);
-
+static void e_select_names_text_model_init (ESelectNamesTextModel *model);
static void e_select_names_text_model_destroy (GtkObject *object);
static void e_select_names_text_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
static void e_select_names_text_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
-static void e_select_names_text_model_set_text (ETextModel *model, const gchar *text);
-static void e_select_names_text_model_insert (ETextModel *model, gint position, const gchar *text);
-static void e_select_names_text_model_insert_length (ETextModel *model, gint position, const gchar *text, gint length);
-static void e_select_names_text_model_delete (ETextModel *model, gint position, gint length);
+static void e_select_names_text_model_set_source (ESelectNamesTextModel *model, ESelectNamesModel *source);
+
+static const gchar *e_select_names_text_model_get_text (ETextModel *model);
+static void e_select_names_text_model_set_text (ETextModel *model, const gchar *text);
+static void e_select_names_text_model_insert (ETextModel *model, gint position, const gchar *text);
+static void e_select_names_text_model_insert_length (ETextModel *model, gint position, const gchar *text, gint length);
+static void e_select_names_text_model_delete (ETextModel *model, gint position, gint length);
static gint e_select_names_text_model_obj_count (ETextModel *model);
static const gchar *e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len);
static void e_select_names_text_model_activate_obj (ETextModel *model, gint n);
-static void e_select_names_text_model_model_changed (ESelectNamesModel *source,
- ESelectNamesTextModel *model);
-
ETextModelClass *parent_class;
#define PARENT_TYPE e_text_model_get_type()
@@ -76,23 +82,6 @@ e_select_names_text_model_get_type (void)
return model_type;
}
-/**
- * e_select_names_text_model_new:
- * @VCard: a string in vCard format
- *
- * Returns: a new #ESelectNamesTextModel that wraps the @VCard.
- */
-ETextModel *
-e_select_names_text_model_new (ESelectNamesModel *source)
-{
- ETextModel *model = E_TEXT_MODEL(gtk_type_new(e_select_names_text_model_get_type()));
- gtk_object_set(GTK_OBJECT(model),
- "source", source,
- NULL);
- e_select_names_text_model_model_changed (source, E_SELECT_NAMES_TEXT_MODEL(model));
- return model;
-}
-
static void
e_select_names_text_model_class_init (ESelectNamesTextModelClass *klass)
{
@@ -111,6 +100,7 @@ e_select_names_text_model_class_init (ESelectNamesTextModelClass *klass)
object_class->get_arg = e_select_names_text_model_get_arg;
object_class->set_arg = e_select_names_text_model_set_arg;
+ text_model_class->get_text = e_select_names_text_model_get_text;
text_model_class->set_text = e_select_names_text_model_set_text;
text_model_class->insert = e_select_names_text_model_insert;
text_model_class->insert_length = e_select_names_text_model_insert_length;
@@ -119,323 +109,590 @@ e_select_names_text_model_class_init (ESelectNamesTextModelClass *klass)
text_model_class->obj_count = e_select_names_text_model_obj_count;
text_model_class->get_nth_obj = e_select_names_text_model_get_nth_obj;
text_model_class->object_activated = e_select_names_text_model_activate_obj;
+
+ if (getenv ("EVO_DEBUG_SELECT_NAMES_TEXT_MODEL")) {
+ out = fopen ("/tmp/evo-debug-select-names-text-model", "w");
+ if (out)
+ setvbuf (out, NULL, _IONBF, 0);
+ }
}
-static int
-get_length(EIterator *iterator)
+static void
+dump_model (ESelectNamesTextModel *text_model)
{
- const ESelectNamesModelData *data = e_iterator_get(iterator);
- return strlen(data->string);
+ ESelectNamesModel *model = text_model->source;
+ gint i;
+
+ 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)
+ fprintf (out, "[%d] \"%s\" %s\n", i,
+ e_select_names_model_get_string (model, i),
+ e_select_names_model_get_card (model, i) ? "<card>" : "");
+ fprintf (out, "\n");
}
static void
-e_select_names_text_model_set_text (ETextModel *model, const gchar *text)
+e_select_names_text_model_init (ESelectNamesTextModel *model)
{
- ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL(model)->source;
- EIterator *iterator = e_list_get_iterator(e_select_names_model_get_data(source));
- int length = e_text_model_get_text_length (model);
+}
+
+static void
+e_select_names_text_model_destroy (GtkObject *object)
+{
+ ESelectNamesTextModel *model;
- e_iterator_reset(iterator);
- if (!e_iterator_is_valid(iterator)) {
- gtk_object_unref(GTK_OBJECT(iterator));
- iterator = NULL;
- }
- e_select_names_model_replace(source,
- iterator,
- 0,
- length,
- (gchar *) text);
- if (iterator)
- gtk_object_unref(GTK_OBJECT(iterator));
+ model = E_SELECT_NAMES_TEXT_MODEL (object);
+
+ e_select_names_text_model_set_source (model, NULL);
+
+ if (GTK_OBJECT_CLASS(parent_class)->destroy)
+ GTK_OBJECT_CLASS(parent_class)->destroy(object);
}
static void
-e_select_names_text_model_insert (ETextModel *model, gint position, const gchar *text)
+e_select_names_text_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
- ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL(model)->source;
- EIterator *iterator = e_list_get_iterator(e_select_names_model_get_data(source));
+ ESelectNamesTextModel *model;
+
+ model = E_SELECT_NAMES_TEXT_MODEL (object);
- for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) {
- int this_length = get_length(iterator);
- if (position <= this_length) {
- break;
- } else {
- position -= this_length + 1;
- }
- }
- if (!e_iterator_is_valid(iterator)) {
- gtk_object_unref(GTK_OBJECT(iterator));
- iterator = NULL;
+ switch (arg_id) {
+ case ARG_SOURCE:
+ e_select_names_text_model_set_source(model, E_SELECT_NAMES_MODEL (GTK_VALUE_OBJECT (*arg)));
+ break;
+ default:
+ return;
}
- e_select_names_model_insert(source,
- iterator,
- position,
- (gchar *) text);
- if (iterator)
- gtk_object_unref(GTK_OBJECT(iterator));
}
static void
-e_select_names_text_model_insert_length (ETextModel *model, gint position, const gchar *text, gint length)
+e_select_names_text_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
- ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL(model)->source;
- EIterator *iterator = e_list_get_iterator(e_select_names_model_get_data(source));
+ ESelectNamesTextModel *model;
- for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) {
- int this_length = get_length(iterator);
- if (position <= this_length) {
- break;
- } else {
- position -= this_length + 1;
- }
- }
- if (!e_iterator_is_valid(iterator)) {
- gtk_object_unref(GTK_OBJECT(iterator));
- iterator = NULL;
+ model = E_SELECT_NAMES_TEXT_MODEL (object);
+
+ switch (arg_id) {
+ case ARG_SOURCE:
+ GTK_VALUE_OBJECT(*arg) = GTK_OBJECT(model->source);
+ break;
+ default:
+ arg->type = GTK_TYPE_INVALID;
+ break;
}
- e_select_names_model_insert_length(source,
- iterator,
- position,
- (gchar *) text,
- length);
- if (iterator)
- gtk_object_unref(GTK_OBJECT(iterator));
}
static void
-e_select_names_text_model_delete (ETextModel *model, gint position, gint length)
+resize_cb (ESelectNamesModel *source, gint index, gint old_len, gint new_len, ETextModel *model)
{
- ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL(model)->source;
- EIterator *iterator = e_list_get_iterator(e_select_names_model_get_data(source));
-
- for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) {
- int this_length = get_length(iterator);
- if (position <= this_length) {
- e_select_names_model_delete(source,
- iterator,
- position,
- length);
- break;
- } else {
- position -= this_length + 1;
- }
+ EReposDeleteShift repos_del;
+ EReposInsertShift repos_ins;
+ gint pos;
+
+ e_select_names_model_name_pos (source, index, &pos, NULL);
+
+ if (new_len < old_len) {
+
+ repos_del.model = model;
+ repos_del.pos = pos;
+ repos_del.len = old_len - new_len;
+ e_text_model_reposition (model, e_repos_delete_shift, &repos_del);
+
+ } else if (old_len < new_len) {
+
+ repos_ins.model = model;
+ repos_ins.pos = pos;
+ repos_ins.len = new_len - old_len;
+ e_text_model_reposition (model, e_repos_insert_shift, &repos_ins);
+
}
- if (iterator)
- gtk_object_unref(GTK_OBJECT(iterator));
}
-static gint
-e_select_names_text_model_obj_count (ETextModel *model)
+
+static void
+e_select_names_text_model_set_source (ESelectNamesTextModel *model,
+ ESelectNamesModel *source)
{
- ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
- EIterator *iterator = e_list_get_iterator (e_select_names_model_get_data (source));
- gint count = 0;
+ if (source == model->source)
+ return;
- for (e_iterator_reset (iterator); e_iterator_is_valid (iterator); e_iterator_next (iterator)) {
- const ESelectNamesModelData *data = e_iterator_get (iterator);
- if (data->type == E_SELECT_NAMES_MODEL_DATA_TYPE_CARD)
- ++count;
+ if (model->source) {
+ gtk_signal_disconnect (GTK_OBJECT (model->source), model->source_changed_id);
+ gtk_signal_disconnect (GTK_OBJECT (model->source), model->source_resize_id);
+ gtk_object_unref (GTK_OBJECT (model->source));
}
- return count;
+ model->source = source;
+
+ if (model->source) {
+ 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_OBJECT (model));
+ model->source_resize_id = gtk_signal_connect (GTK_OBJECT(model->source),
+ "resized",
+ GTK_SIGNAL_FUNC (resize_cb),
+ model);
+ }
+}
+
+ETextModel *
+e_select_names_text_model_new (ESelectNamesModel *source)
+{
+ ETextModel *model = E_TEXT_MODEL (gtk_type_new (e_select_names_text_model_get_type()));
+ e_select_names_text_model_set_source (E_SELECT_NAMES_TEXT_MODEL (model), source);
+ return model;
}
static const gchar *
-e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len)
+e_select_names_text_model_get_text (ETextModel *model)
{
- ESelectNamesTextModel *select_text_model = E_SELECT_NAMES_TEXT_MODEL (model);
- ESelectNamesModel *source = select_text_model->source;
- EIterator *iterator = e_list_get_iterator (e_select_names_model_get_data (source));
- const ESelectNamesModelData *data;
- gint i, pos;
-
- pos = 0;
- i = 0;
- e_iterator_reset (iterator);
- while (e_iterator_is_valid (iterator) && n > 0) {
- gint len;
- data = e_iterator_get (iterator);
- len = strlen (data->string);
+ ESelectNamesTextModel *snm = E_SELECT_NAMES_TEXT_MODEL(model);
- pos += len + 1; /* advance and extra space for comma */
- ++i;
- if (data->type == E_SELECT_NAMES_MODEL_DATA_TYPE_CARD)
- --n;
+ return snm ? e_select_names_model_get_textification (snm->source) : "";
+}
- if (n >= 0)
- e_iterator_next (iterator);
- }
+static void
+e_select_names_text_model_set_text (ETextModel *model, const gchar *text)
+{
+ ESelectNamesTextModel *snm = E_SELECT_NAMES_TEXT_MODEL(model);
- if (len) {
- data = e_iterator_get (iterator);
- *len = strlen (data->string);
- }
+ e_select_names_model_delete_all (snm->source);
+ e_select_names_text_model_insert (model, 0, text);
+}
- return e_text_model_get_text (model) + pos;
+static void
+e_select_names_text_model_insert (ETextModel *model, gint position, const gchar *text)
+{
+ e_select_names_text_model_insert_length (model, position, text, strlen (text));
}
static void
-e_select_names_text_model_activate_obj (ETextModel *model, gint n)
+e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gchar *text, gint length)
{
- ESelectNamesTextModel *select_text_model = E_SELECT_NAMES_TEXT_MODEL (model);
- ESelectNamesModel *source = select_text_model->source;
- EIterator *iterator = e_list_get_iterator (e_select_names_model_get_data (source));
- const ESelectNamesModelData *data;
- const ECard *card;
- EContactEditor *contact_editor;
+ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
+ gint i;
- e_iterator_reset (iterator);
- while (e_iterator_is_valid (iterator) && n > 0) {
- data = e_iterator_get (iterator);
- if (data->type == E_SELECT_NAMES_MODEL_DATA_TYPE_CARD)
- --n;
+ g_return_if_fail (model != NULL);
+ g_return_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (model));
- if (n >= 0)
- e_iterator_next (iterator);
+ if (out) {
+ gchar *tmp = g_strndup (text, length);
+ fprintf (out, ">> insert \"%s\" (len=%d) at %d\n", tmp, length, pos);
+ g_free (tmp);
}
- data = e_iterator_get (iterator);
- card = E_CARD (data->card);
+ pos = CLAMP (pos, 0, strlen (e_select_names_model_get_textification (source)));
- /* FIXME: const incorrectness here. */
- contact_editor = e_contact_editor_new ((ECard *) card, FALSE);
- e_contact_editor_raise (contact_editor);
+ /* 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);
+
+ /* We handle this one character at a time. */
+
+ for (i = 0; i < length && text[i]; ++i) {
+ gint index, start_pos, text_len;
+
+ if (out)
+ fprintf (out, "processing [%c]\n", text[i]);
+
+ e_select_names_model_text_pos (source, 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] == ',') {
+
+ /* This is the case of hitting , first thing in an empty entry */
+ if (index == -1) {
+ EReposAbsolute repos;
+
+ e_select_names_model_insert (source, 0, e_destination_new ());
+ e_select_names_model_insert (source, 0, e_destination_new ());
+
+ repos.model = model;
+ repos.pos = -1; /* At end */
+ e_text_model_reposition (model, e_repos_absolute, &repos);
+
+
+ } else if (pos <= start_pos || pos == start_pos + text_len) {
+ EReposInsertShift repos;
+ gint ins_point = index;
+
+ if (text_len != 0 && pos == start_pos + text_len)
+ ++ins_point;
+
+ /* Block adjacent blank cards. */
+ if (! ((ins_point < e_select_names_model_count (source) &&
+ (e_select_names_model_get_string (source, ins_point) == NULL))
+ || (ins_point > 0 && (e_select_names_model_get_string (source, ins_point-1) == NULL)))) {
+
+ e_select_names_model_insert (source, ins_point, e_destination_new ());
+
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = SEPLEN;
+ e_text_model_reposition (model, e_repos_insert_shift, &repos);
+ }
+
+ } else {
+ EReposInsertShift repos;
+ gint offset = MAX (pos - start_pos, 0);
+ const gchar *str = e_select_names_model_get_string (source, index);
+ gchar *str1 = g_strndup (str, offset);
+ gchar *str2 = g_strdup (str+offset);
+ EDestination *d1 = e_destination_new (), *d2 = e_destination_new ();
+
+ e_destination_set_string (d1, str1);
+ e_destination_set_string (d2, str2);
+
+ e_select_names_model_replace (source, index, d1);
+ e_select_names_model_insert (source, index+1, d2);
+
+ g_free (str1);
+ g_free (str2);
+
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = SEPLEN;
+ e_text_model_reposition (model, e_repos_insert_shift, &repos);
+ }
+
+ } else {
+ EReposInsertShift repos;
+ gint offset = MAX (pos - start_pos, 0);
+ const gchar *str;
+ gchar *new_str = NULL;
+ gint this_length = 1;
+ gboolean whitespace = isspace ((gint) text[i]);
+
+ str = index >= 0 ? e_select_names_model_get_string (source, index) : NULL;
+ if (str) {
+ if (pos <= start_pos) {
+ if (whitespace) {
+ /* swallow leading whitespace */
+ this_length = 0;
+ } else {
+ /* Adjust for our "magic white space" */
+ new_str = g_strdup_printf("%c%s%s", text[i], pos < start_pos ? " " : "", str);
+ if (pos < start_pos)
+ ++this_length;
+ }
+ } else {
+ new_str = g_strdup_printf ("%.*s%c%s", offset, str, text[i], str + offset);
+ }
+ } else {
+ if (whitespace) {
+ /* swallow leading whitespace */
+ this_length = 0;
+ } else {
+ new_str = g_strdup_printf ("%c", text[i]);
+ }
+ }
+
+ if (new_str) {
+
+ EDestination *dest = e_destination_new ();
+ e_destination_set_string (dest, new_str);
+
+ e_select_names_model_replace (source, index, dest);
+
+ if (this_length > 0) {
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = this_length;
+ e_text_model_reposition (model, e_repos_insert_shift, &repos);
+ }
+
+ g_free (new_str);
+ }
+
+ }
+ }
+
+ dump_model (E_SELECT_NAMES_TEXT_MODEL (model));
+
+ gtk_signal_handler_unblock (GTK_OBJECT (source), E_SELECT_NAMES_TEXT_MODEL (model)->source_resize_id);
}
+
static void
-e_select_names_text_model_model_changed (ESelectNamesModel *source,
- ESelectNamesTextModel *model)
+e_select_names_text_model_delete (ETextModel *model, gint pos, gint length)
{
- EList *list = e_select_names_model_get_data(source);
- EIterator *iterator = e_list_get_iterator(list);
- int length = 0;
- int length_count = 0;
- int *lengthsp;
- char *string;
- char *stringp;
- for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) {
- const ESelectNamesModelData *data = e_iterator_get(iterator);
- length += strlen(data->string);
- length ++;
- length_count++;
+ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
+ gint index, start_pos, text_len, offset;
+
+ if (out) {
+ const gchar *str = e_select_names_model_get_textification (source);
+ gint i, len;
+
+ fprintf (out, ">> delete %d at pos %d\n", length, pos);
+
+ len = strlen (str);
+ for (i=0; i<pos && i<len; ++i)
+ fprintf (out, "%c", str[i]);
+ fprintf (out, "[");
+ for (i=pos; i<pos+length && i<len; ++i)
+ fprintf (out, "%c", str[i]);
+ fprintf (out, "]");
+ for (i=pos+length; i<len; ++i)
+ fprintf (out, "%c", str[i]);
+ fprintf (out, "\n");
}
- if (length > 0)
- length --;
-
- g_free(model->lengths);
- model->lengths = g_new(int, length_count + 1);
- lengthsp = model->lengths;
-
- string = g_new(char, length + 1);
- stringp = string;
- *stringp = 0;
- for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) {
- const ESelectNamesModelData *data = e_iterator_get(iterator);
- int this_length;
-
- strcpy(stringp, data->string);
- this_length = strlen(stringp);
- stringp += this_length;
- *(stringp++) = ',';
- *(lengthsp++) = this_length;
+
+ if (length < 0)
+ return;
+
+ e_select_names_model_text_pos (source, pos, &index, &start_pos, &text_len);
+
+ if (out)
+ fprintf (out, "index=%d, start_pos=%d, text_len=%d\n", index, start_pos, text_len);
+
+ /* 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);
+
+ /* First, we handle a few tricky cases. */
+
+ if (pos < start_pos) {
+ EReposAbsolute repos;
+
+ repos.model = model;
+ repos.pos = pos;
+ e_text_model_reposition (model, e_repos_absolute, &repos);
+
+ length -= start_pos - pos;
+
+ if (length > 0)
+ e_select_names_text_model_delete (model, start_pos, length);
+ goto finished;
}
- if (stringp != string) {
- stringp --;
- *stringp = 0;
+
+ if (pos == start_pos + text_len) {
+ /* We are positioned right at the end of an entry, possibly right in front of a comma. */
+
+ if (index+1 < e_select_names_model_count (source)) {
+ EReposDeleteShift repos;
+ EDestination *new_dest;
+ const gchar *str1 = e_select_names_model_get_string (source, index);
+ const gchar *str2 = e_select_names_model_get_string (source, index+1);
+ gchar *new_str;
+
+ while (str1 && *str1 && isspace ((gint) *str1))
+ ++str1;
+ while (str2 && *str2 && isspace ((gint) *str2))
+ ++str2;
+
+ if (str1 && str2)
+ new_str = g_strdup_printf ("%s %s", str1, str2);
+ else if (str1)
+ new_str = g_strdup (str1);
+ else if (str2)
+ new_str = g_strdup (str2);
+ else
+ new_str = g_strdup ("");
+
+ if (out)
+ fprintf (out, "joining \"%s\" and \"%s\" to \"%s\"\n", str1, str2, new_str);
+
+ e_select_names_model_delete (source, index+1);
+
+ new_dest = e_destination_new ();
+ e_destination_set_string (new_dest, new_str);
+ e_select_names_model_replace (source, index, new_dest);
+ g_free (new_str);
+
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = SEPLEN - 1;
+
+ e_text_model_reposition (model, e_repos_delete_shift, &repos);
+
+ if (length > 1)
+ e_select_names_text_model_delete (model, pos, length-1);
+ } else {
+ /* If we are at the end of the last entry (which we must be if we end up in this block),
+ we can just do nothing. So this else-block is here just to give us a place to
+ put this comment. */
+ }
+
+ goto finished;
}
- *lengthsp = -1;
+
+ if (pos + length > start_pos + text_len) {
+ /* Uh oh... our changes straddle two objects. */
- E_TEXT_MODEL_CLASS (parent_class)->set_text (E_TEXT_MODEL (model), string);
- g_free (string);
-}
+ if (pos == start_pos) { /* Delete the whole thing */
+ EReposDeleteShift repos;
+
+ e_select_names_model_delete (source, index);
+ if (out)
+ fprintf (out, "deleted all of %d\n", index);
-static void
-e_select_names_text_model_add_source (ESelectNamesTextModel *model,
- ESelectNamesModel *source)
-{
- model->source = source;
- if (model->source)
- gtk_object_ref(GTK_OBJECT(model->source));
- model->source_changed_id = gtk_signal_connect(GTK_OBJECT(model->source), "changed",
- GTK_SIGNAL_FUNC(e_select_names_text_model_model_changed),
- model);
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = text_len + SEPLEN;
+
+ e_text_model_reposition (model, e_repos_delete_shift, &repos);
+
+ length -= text_len + SEPLEN;
+ if (length > 0)
+ e_select_names_text_model_delete (model, pos, length);
+
+ } else {
+ /* Delete right up to the end, and then call e_select_names_text_model_delete again
+ to finish the job. */
+ gint len1, len2;
+
+ len1 = text_len - (pos - start_pos);
+ len2 = length - len1;
+
+ if (out)
+ fprintf (out, "two-stage delete: %d, %d\n", len1, len2);
+
+
+ e_select_names_text_model_delete (model, pos, len1);
+ e_select_names_text_model_delete (model, pos, len2);
+ }
+
+ goto finished;
+ }
+
+ /* Our changes are confined to just one entry. */
+ if (length > 0) {
+ const gchar *str;
+ gchar *new_str;
+
+ offset = pos - start_pos;
+
+ str = e_select_names_model_get_string (source, index);
+ new_str = str ? g_strdup_printf ("%.*s%s", offset, str, str + offset + length) : NULL;
+
+ if (new_str) {
+ EReposDeleteShift repos;
+ EDestination *dest;
+
+ dest = e_destination_new ();
+ e_destination_set_string (dest, new_str);
+ e_select_names_model_replace (source, index, dest);
+
+ if (out)
+ fprintf (out, "new_str: \"%s\"\n", new_str);
+
+ g_free (new_str);
+
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = length;
+
+ e_text_model_reposition (model, e_repos_delete_shift, &repos);
+
+ } else {
+ EReposDeleteShift repos;
+
+ e_select_names_model_delete (source, index);
+
+ if (out)
+ fprintf (out, "deleted %d\n", index);
+
+
+ repos.model = model;
+ repos.pos = pos;
+ repos.len = SEPLEN;
+
+ e_text_model_reposition (model, e_repos_delete_shift, &repos);
+ }
+ }
+
+ finished:
+ gtk_signal_handler_unblock (GTK_OBJECT (source), E_SELECT_NAMES_TEXT_MODEL (model)->source_resize_id);
+ dump_model (E_SELECT_NAMES_TEXT_MODEL (model));
}
-static void
-e_select_names_text_model_drop_source (ESelectNamesTextModel *model)
+static gint
+e_select_names_text_model_obj_count (ETextModel *model)
{
- if (model->source_changed_id)
- gtk_signal_disconnect(GTK_OBJECT(model->source), model->source_changed_id);
- if (model->source)
- gtk_object_unref(GTK_OBJECT(model->source));
- model->source = NULL;
- model->source_changed_id = 0;
-}
+ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
+ gint i, count;
+
+ count = i = e_select_names_model_count (source);
+ while (i > 0) {
+ const EDestination *dest;
+ --i;
+ dest = e_select_names_model_get_destination (source, i);
+ if (e_destination_get_card (dest) == NULL)
+ --count;
+ }
-/*
- * ESelectNamesTextModel lifecycle management and vcard loading/saving.
- */
+ return count;
+}
-static void
-e_select_names_text_model_destroy (GtkObject *object)
+static gint
+nth_obj_index (ESelectNamesModel *source, gint n)
{
- ESelectNamesTextModel *model;
-
- model = E_SELECT_NAMES_TEXT_MODEL (object);
-
- e_select_names_text_model_drop_source(model);
- g_free(model->lengths);
+ gint i, N;
+
+ i = 0;
+ N = e_select_names_model_count (source);
- if (GTK_OBJECT_CLASS(parent_class)->destroy)
- GTK_OBJECT_CLASS(parent_class)->destroy(object);
-}
+ do {
+ const EDestination *dest = e_select_names_model_get_destination (source, i);
+ if (e_destination_get_card (dest))
+ --n;
+ ++i;
+ } while (n >= 0 && i < N);
+ if (i <= N)
+ --i;
+ else
+ i = -1;
-/* Set_arg handler for the model */
-static void
-e_select_names_text_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+ return i;
+}
+
+static const gchar *
+e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len)
{
- ESelectNamesTextModel *model;
-
- model = E_SELECT_NAMES_TEXT_MODEL (object);
+ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
+ const gchar *txt;
+ gint i, pos;
- switch (arg_id) {
- case ARG_SOURCE:
- e_select_names_text_model_drop_source(model);
- e_select_names_text_model_add_source(model, E_SELECT_NAMES_MODEL(GTK_VALUE_OBJECT(*arg)));
- break;
- default:
- return;
- }
+ i = nth_obj_index (source, n);
+ if (i < 0)
+ return NULL;
+
+ e_select_names_model_name_pos (source, i, &pos, len);
+ if (pos < 0)
+ return NULL;
+
+ txt = e_select_names_model_get_textification (source);
+ return txt + pos;
}
-/* Get_arg handler for the model */
static void
-e_select_names_text_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+e_select_names_text_model_activate_obj (ETextModel *model, gint n)
{
- ESelectNamesTextModel *model;
+ ESelectNamesModel *source = E_SELECT_NAMES_TEXT_MODEL (model)->source;
+ EContactEditor *contact_editor;
+ ECard *card;
+ gint i;
- model = E_SELECT_NAMES_TEXT_MODEL (object);
+ i = nth_obj_index (source, n);
+ g_return_if_fail (i >= 0);
- switch (arg_id) {
- case ARG_SOURCE:
- GTK_VALUE_OBJECT(*arg) = GTK_OBJECT(model->source);
- break;
- default:
- arg->type = GTK_TYPE_INVALID;
- break;
- }
+ card = e_select_names_model_get_card (source, i);
+ g_return_if_fail (card);
+
+ contact_editor = e_contact_editor_new ((ECard *) card, FALSE);
+ e_contact_editor_raise (contact_editor);
}
-/**
- * e_select_names_text_model_init:
- */
-static void
-e_select_names_text_model_init (ESelectNamesTextModel *model)
-{
- model->source = NULL;
- model->source_changed_id = 0;
- model->lengths = NULL;
-}
+