aboutsummaryrefslogblamecommitdiffstats
path: root/addressbook/gui/component/select-names/e-select-names-model.c
blob: 138b0d73ad3c814324b85cf70e32cb465dad4335 (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                                                                           

                                        
  
                                        


                   
 


                   
                           
                          
 
                            

                                 
                                                    
 
                      
                                     
 

                       
 

                                     
                                     










                                                                                    

















                                           

                   


                                 


  






                                                                                        






















                                                                                   





                                                                                                                     
 






                                                   

 
 














                                                                                    







                                                                                            











                                                                                                                    

                             
   



                                                                   

                                
 



                                                
                                                                 
        









                                                                           
 



































                                                                           









                                                       





                                                                                                                

 





                                                                      
                                                                               
 

                               
 


                                                                                       

 

                                                       
 

                                                                                                       
 




                                                                                    
                                                         

         

                                              
                     

 

                                                                 
 















                                                                                             
                                                                                     




                                                                         




                                                                              





                                      

 

                                                                
 








                                                                     
                        





                                                                                             
                                                                                     







                                                                              
                 
         

                                      

 

                                                     
 



                                                                  
 
 


























                                                                                                  

                                                                           
 
                                                                              



                                                                               

 












                                                                              



                                                             







                                            


















                                                                     



                          






                                                                       

                                                                    
 
                                 
 





                                                                               
 

 

                                                                      
 







                                                                               
                                                            

 














                                                                                            
        
                                                                                  













                                                                                                 
    
                                                                                      
 




                                                                                    





                                                     

                                          





                                                                           


    




                                                                          





                                                     

                                          








                                                                    
                                                                                       
 
                    
                                       
                                        
 




                                                                                                                  

                                                    
 
                                        
 

                                                  
                                                                            


                                                    
                

                                                             
 
                                         
 


                                                                                   

                                                                                         





                                                                   

                 




                                                                                                        

 

                                                                  
 
                    
                           
 




                                                                                   



                                             
 

                                                                         
 
                                             
 

    















                                                                            

                                                                     
                                                                     
                         











                                                                                         






                                                                                      
    
                                                          
 
                                                                            
 
                                                                   



                                             


    



















                                                                                      


















                                                                                      
                                                                                             
 

                                
                         







                                                           

                                                                             












                                          


    
                                                                                                              
 
                    
                         





                                                           
 
                              

                                                                             

                                                         
                              
                 











                                                   


                                                  


                        



                                                       








                                




















                                                                                            
























                                                                                              













































                                                                                    

















                                                           
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Authors: 
 *   Chris Lahey     <clahey@ximian.com>
 *   Jon Trowbidge   <trow@ximian.com>
 *
 * Copyright (C) 2000, 2001 Ximian, Inc.
 */

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtkmarshal.h>
#include <gtk/gtksignal.h>

#include <gal/util/e-util.h>

#include "e-select-names-model.h"
#include "addressbook/backend/ebook/e-card-simple.h"

#define SEPARATOR ", "
#define SEPLEN    (strlen(SEPARATOR))

#define MAX_LENGTH 2047


enum {
    E_SELECT_NAMES_MODEL_CHANGED,
    E_SELECT_NAMES_MODEL_RESIZED,
    E_SELECT_NAMES_MODEL_LAST_SIGNAL
};

static guint e_select_names_model_signals[E_SELECT_NAMES_MODEL_LAST_SIGNAL] = { 0 };

/* Object argument IDs */
enum {
    ARG_0,
    ARG_CARD,
};

enum {
    NAME_DATA_BLANK,
    NAME_DATA_CARD,
    NAME_DATA_STRING
};

enum {
    NAME_FORMAT_GIVEN_FIRST,
    NAME_FORMAT_FAMILY_FIRST
};

struct _ESelectNamesModelPrivate {
    gchar *id;
    gchar *title;

    GList *data;  /* of EDestination */
    gchar *text;
    gchar *addr_text;

    gint limit;

    gint freeze_count;
    gboolean pending_changed;
};


static void e_select_names_model_init (ESelectNamesModel *model);
static void e_select_names_model_class_init (ESelectNamesModelClass *klass);

static void e_select_names_model_destroy (GtkObject *object);
static void e_select_names_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
static void e_select_names_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);

GtkType
e_select_names_model_get_type (void)
{
    static GtkType model_type = 0;

    if (!model_type) {
        GtkTypeInfo model_info = {
            "ESelectNamesModel",
            sizeof (ESelectNamesModel),
            sizeof (ESelectNamesModelClass),
            (GtkClassInitFunc) e_select_names_model_class_init,
            (GtkObjectInitFunc) e_select_names_model_init,
            NULL, /* reserved_1 */
            NULL, /* reserved_2 */
            (GtkClassInitFunc) NULL
        };

        model_type = gtk_type_unique (gtk_object_get_type (), &model_info);
    }

    return model_type;
}

typedef void (*GtkSignal_NONE__INT_INT_INT) (GtkObject *object, gint arg1, gint arg2, gint arg3, gpointer user_data);
static void
local_gtk_marshal_NONE__INT_INT_INT (GtkObject    *object, 
                     GtkSignalFunc func, 
                     gpointer      func_data, 
                     GtkArg       *args)
{
    GtkSignal_NONE__INT_INT_INT rfunc;
    rfunc = (GtkSignal_NONE__INT_INT_INT) func;
    (* rfunc) (object,
           GTK_VALUE_INT(args[0]),
           GTK_VALUE_INT(args[1]),
           GTK_VALUE_INT(args[2]),
           func_data);
}


static void
e_select_names_model_class_init (ESelectNamesModelClass *klass)
{
    GtkObjectClass *object_class;

    object_class = GTK_OBJECT_CLASS(klass);

    e_select_names_model_signals[E_SELECT_NAMES_MODEL_CHANGED] =
        gtk_signal_new ("changed",
                GTK_RUN_LAST,
                object_class->type,
                GTK_SIGNAL_OFFSET (ESelectNamesModelClass, changed),
                gtk_marshal_NONE__NONE,
                GTK_TYPE_NONE, 0);

    e_select_names_model_signals[E_SELECT_NAMES_MODEL_RESIZED] =
        gtk_signal_new ("resized",
                GTK_RUN_LAST,
                object_class->type,
                GTK_SIGNAL_OFFSET (ESelectNamesModelClass, resized),
                local_gtk_marshal_NONE__INT_INT_INT,
                GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);

    gtk_object_class_add_signals (object_class, e_select_names_model_signals, E_SELECT_NAMES_MODEL_LAST_SIGNAL);

    gtk_object_add_arg_type ("ESelectNamesModel::card",
                 GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_CARD);

    klass->changed = NULL;

    object_class->destroy = e_select_names_model_destroy;
    object_class->get_arg = e_select_names_model_get_arg;
    object_class->set_arg = e_select_names_model_set_arg;
}

/**
 * e_select_names_model_init:
 */
static void
e_select_names_model_init (ESelectNamesModel *model)
{
    model->priv = g_new0 (struct _ESelectNamesModelPrivate, 1);

    model->priv->limit = -1;
}

static void
e_select_names_model_destroy (GtkObject *object)
{
    ESelectNamesModel *model = E_SELECT_NAMES_MODEL (object);
    
    g_free (model->priv->title);
    g_free (model->priv->id);

    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);

}


/* Set_arg handler for the model */
static void
e_select_names_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
    ESelectNamesModel *model;
    
    model = E_SELECT_NAMES_MODEL (object);

    switch (arg_id) {
    case ARG_CARD:
        break;
    default:
        return;
    }
}

/* Get_arg handler for the model */
static void
e_select_names_model_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
    ESelectNamesModel *model;

    model = E_SELECT_NAMES_MODEL (object);

    switch (arg_id) {
    case ARG_CARD:
        break;
    default:
        arg->type = GTK_TYPE_INVALID;
        break;
    }
}


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 {
        gtk_signal_emit (GTK_OBJECT(model), e_select_names_model_signals[E_SELECT_NAMES_MODEL_CHANGED]);
        model->priv->pending_changed = FALSE;
    }
}

static void
destination_changed_proxy (EDestination *dest, gpointer closure)
{
    e_select_names_model_changed (E_SELECT_NAMES_MODEL (closure));
}

/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/

ESelectNamesModel *
e_select_names_model_new (void)
{
    ESelectNamesModel *model;
    model = E_SELECT_NAMES_MODEL (gtk_type_new (e_select_names_model_get_type ()));
    return model;
}

ESelectNamesModel *
e_select_names_model_duplicate (ESelectNamesModel *old)
{
    ESelectNamesModel *model = E_SELECT_NAMES_MODEL(gtk_type_new(e_select_names_model_get_type()));
    GList *iter;

    model->priv->id = g_strdup (old->priv->id);
    model->priv->title = g_strdup (old->priv->title);
    
    for (iter = old->priv->data; iter != NULL; iter = g_list_next (iter)) {
        EDestination *dup = e_destination_copy (E_DESTINATION (iter->data));
        e_select_names_model_append (model, dup);
    }

    model->priv->limit = old->priv->limit;

    return model;
}

const gchar *
e_select_names_model_get_textification (ESelectNamesModel *model)
{
    g_return_val_if_fail (model != NULL, NULL);
    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), 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 (strlen(model->priv->text) > MAX_LENGTH) {
                model->priv->text[MAX_LENGTH] = 0;
                g_realloc (model->priv->text, MAX_LENGTH + 1);
            }
            
            g_free (strv);
        }
    }

    return model->priv->text;
}

const gchar *
e_select_names_model_get_address_text (ESelectNamesModel *model)
{
    g_return_val_if_fail (model != NULL, NULL);
    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), 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);

            g_free (strv);
        }
    }

    return model->priv->addr_text;
}

gint
e_select_names_model_count (ESelectNamesModel *model)
{
    g_return_val_if_fail (model != NULL, 0);
    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), 0);

    return g_list_length (model->priv->data);
}

gint
e_select_names_model_get_limit (ESelectNamesModel *model)
{
    g_return_val_if_fail (model != NULL, 0);
    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), 0);

    return model->priv->limit;
}

void
e_select_names_model_set_limit (ESelectNamesModel *model, gint limit)
{
    g_return_if_fail (model != NULL);
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));

    model->priv->limit = MAX (limit, -1);
}

gboolean
e_select_names_model_at_limit (ESelectNamesModel *model)
{
    g_return_val_if_fail (model != NULL, TRUE);
    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), TRUE);

    return model->priv->limit >= 0 && g_list_length (model->priv->data) >= model->priv->limit;
}

const EDestination *
e_select_names_model_get_destination (ESelectNamesModel *model, gint index)
{
    g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL);
    g_return_val_if_fail (0 <= index, NULL);
    g_return_val_if_fail (index < g_list_length (model->priv->data), NULL);

    return E_DESTINATION (g_list_nth_data (model->priv->data, index));
}

gchar *
e_select_names_model_export_destinationv (ESelectNamesModel *model)
{
    EDestination **destv;
    gchar *str;
    gint i, len = 0;
    GList *j;
    g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL);

    len = g_list_length (model->priv->data);
    destv = g_new0 (EDestination *, len+1);
    
    for (i=0, j = model->priv->data; j != NULL; j = g_list_next (j)) {
        EDestination *dest = E_DESTINATION (j->data);

        if (dest)
            destv[i++] = dest;
    }

    str = e_destination_exportv (destv);
    g_free (destv);

    return str;
}

static
void send_changed (EDestination *dest, ECard *card, gpointer closure)
{
    ESelectNamesModel *model = closure;
    e_select_names_model_changed (model);
}

void
e_select_names_model_import_destinationv (ESelectNamesModel *model,
                      gchar *destinationv)
{
    EDestination **destv;
    gint i;

    g_return_if_fail (model && E_IS_SELECT_NAMES_MODEL (model));

    destv = e_destination_importv (destinationv);

    e_select_names_model_delete_all (model);

    if (destv == NULL)
        return;

    for (i = 0; destv[i]; i++) {
        e_destination_use_card (destv[i], send_changed, model);
        e_select_names_model_append (model, destv[i]);
    }
    g_free (destv);
}

ECard *
e_select_names_model_get_card (ESelectNamesModel *model, gint index)
{
    const EDestination *dest;

    g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL);
    g_return_val_if_fail (0 <= index, NULL);
    g_return_val_if_fail (index < g_list_length (model->priv->data), NULL);

    dest = e_select_names_model_get_destination (model, index);
    return dest ? e_destination_get_card (dest) : NULL;

}

const gchar *
e_select_names_model_get_string (ESelectNamesModel *model, gint index)
{
    const EDestination *dest;

    g_return_val_if_fail (model && E_IS_SELECT_NAMES_MODEL (model), NULL);
    g_return_val_if_fail (0 <= index, NULL);
    g_return_val_if_fail (index < g_list_length (model->priv->data), NULL);

    dest = e_select_names_model_get_destination (model, 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);
}

gboolean
e_select_names_model_contains (ESelectNamesModel *model, const EDestination *dest)
{
    GList *iter;

    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), FALSE);
    g_return_val_if_fail (E_IS_DESTINATION (dest), FALSE);

    for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) {
        if (iter->data != NULL && e_destination_equal (dest, E_DESTINATION (iter->data)))
            return TRUE;
    }

    return FALSE;
}

void
e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination *dest)
{
    g_return_if_fail (model != NULL);
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
    g_return_if_fail (0 <= index && index <= g_list_length (model->priv->data));
    g_return_if_fail (dest && E_IS_DESTINATION (dest));

    if (e_select_names_model_at_limit (model)) {
        /* FIXME: This is bad. */
        gtk_object_unref (GTK_OBJECT (dest));
        return;
    }

    connect_destination (model, dest);

    model->priv->data = g_list_insert (model->priv->data, dest, index);
    
    gtk_object_ref (GTK_OBJECT (dest));
    gtk_object_sink (GTK_OBJECT (dest));

    e_select_names_model_changed (model);
}

void
e_select_names_model_append (ESelectNamesModel *model, EDestination *dest)
{
    g_return_if_fail (model && E_IS_SELECT_NAMES_MODEL (model));
    g_return_if_fail (dest && E_IS_DESTINATION (dest));

    if (e_select_names_model_at_limit (model)) {
        /* FIXME: This is bad. */
        gtk_object_unref (GTK_OBJECT (dest));
        return;
    }

    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));

    e_select_names_model_changed (model);
}

void
e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination *dest)
{
    GList *node;
    const gchar *new_str, *old_str;
    gint old_strlen=0, new_strlen=0;

    g_return_if_fail (model != NULL);
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
    g_return_if_fail (model->priv->data == NULL || (0 <= index && index < g_list_length (model->priv->data)));
    g_return_if_fail (dest && E_IS_DESTINATION (dest));
    
    new_str = e_destination_get_textrep (dest);
    new_strlen = new_str ? strlen (new_str) : 0;

    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));

    } else {
        
        node = g_list_nth (model->priv->data, index);

        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;

            gtk_object_unref (GTK_OBJECT (node->data));

            node->data = dest;
            gtk_object_ref (GTK_OBJECT (dest));
            gtk_object_sink (GTK_OBJECT (dest));
        }
    }

    e_select_names_model_changed (model);

    gtk_signal_emit (GTK_OBJECT (model), e_select_names_model_signals[E_SELECT_NAMES_MODEL_RESIZED],
             index, old_strlen, new_strlen);
}

void
e_select_names_model_delete (ESelectNamesModel *model, gint index)
{
    GList *node;
    EDestination *dest;

    g_return_if_fail (model != NULL);
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
    g_return_if_fail (0 <= index && index < g_list_length (model->priv->data));
    
    node = g_list_nth (model->priv->data, index);
    dest = E_DESTINATION (node->data);

    disconnect_destination (model, dest);
    gtk_object_unref (GTK_OBJECT (dest));

    model->priv->data = g_list_remove_link (model->priv->data, node);
    g_list_free_1 (node);

    e_select_names_model_changed (model);
}

void
e_select_names_model_clean (ESelectNamesModel *model)
{
    GList *iter, *next;
    gboolean changed = FALSE;

    g_return_if_fail (model != NULL && E_IS_SELECT_NAMES_MODEL (model));

    iter = model->priv->data;

    while (iter) {
        EDestination *dest;

        next = g_list_next (iter);
        dest = iter->data ? E_DESTINATION (iter->data) : NULL;

        if (dest == NULL || e_destination_is_empty (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;
        }
        
        iter = next;
    }

    if (changed)
        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, delete_all_iter, model);
    g_list_free (model->priv->data);
    model->priv->data = NULL;

    e_select_names_model_changed (model);
}

void
e_select_names_model_overwrite_copy (ESelectNamesModel *dest, ESelectNamesModel *src)
{
    gint i, len;

    g_return_if_fail (dest && E_IS_SELECT_NAMES_MODEL (dest));
    g_return_if_fail (src && E_IS_SELECT_NAMES_MODEL (src));

    if (src == dest)
        return;

    e_select_names_model_delete_all (dest);
    len = e_select_names_model_count (src);
    for (i = 0; i < len; ++i) {
        const EDestination *d = e_select_names_model_get_destination (src, i);
        if (d)
            e_select_names_model_append (dest, e_destination_copy (d));
    }
}

void
e_select_names_model_merge (ESelectNamesModel *dest, ESelectNamesModel *src)
{
    gint i, len;

    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (dest));
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (src));

    if (src == dest)
        return;

    len = e_select_names_model_count (src);
    for (i = 0; i < len; ++i) {
        const EDestination *d = e_select_names_model_get_destination (src, i);
        if (d && !e_select_names_model_contains (dest, d))
            e_select_names_model_append (dest, e_destination_copy (d));
    }
}

void
e_select_names_model_name_pos (ESelectNamesModel *model, 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));

    i = 0;
    iter = model->priv->data;
    while (iter && i <= index) {
        rp += len + (i > 0 ? SEPLEN : 0);
        str = e_destination_get_textrep (E_DESTINATION (iter->data));
        len = str ? strlen (str) : 0;
        ++i;
        iter = g_list_next (iter);
    }
    
    if (i <= index) {
        rp = -1;
        len = 0;
    }
    
    if (pos)
        *pos = rp;
    if (length)
        *length = len;
}

void
e_select_names_model_text_pos (ESelectNamesModel *model, 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));

    iter = model->priv->data;

    while (iter != NULL) {
        str = e_destination_get_textrep (E_DESTINATION (iter->data));
        len = str ? strlen (str) : 0;

        if (sp <= pos && pos <= sp + len + adj) {
            break;
        }

        sp += len + adj + 1;
        adj = 1;
        ++i;

        iter = g_list_next (iter);
    }

    if (i != 0)
        ++sp; /* skip past "magic space" */

    if (iter == NULL) {
#if 0
        g_print ("text_pos ended NULL\n");
#endif
        i = -1;
        sp = -1;
        len = 0;
    } else {
#if 0
        g_print ("text_pos got index %d\n", i);
#endif
    }

    if (index)
        *index = i;
    if (start_pos)
        *start_pos = sp;
    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);
    }
}

gboolean
e_select_names_model_uncardify (ESelectNamesModel *model, gint index)
{
    EDestination *dest;
    gboolean rv = FALSE;

    g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), FALSE);
    g_return_val_if_fail (0 <= index && index < g_list_length (model->priv->data), FALSE);

    dest = E_DESTINATION (g_list_nth_data (model->priv->data, index));

    if (!e_destination_is_empty (dest)) {
        EDestination *cpy_dest = e_destination_copy (dest);

        rv = e_destination_uncardify (cpy_dest);

        if (rv) {
            e_select_names_model_replace (model, index, cpy_dest);
        }
        
    }

    return rv;
}

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);
    }
}

void
e_select_names_model_freeze (ESelectNamesModel *model)
{
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
    
    ++model->priv->freeze_count;
}

void
e_select_names_model_thaw (ESelectNamesModel *model)
{
    g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
    g_return_if_fail (model->priv->freeze_count > 0);

    --model->priv->freeze_count;
    if (model->priv->pending_changed)
        e_select_names_model_changed (model);
}