aboutsummaryrefslogblamecommitdiffstats
path: root/addressbook/gui/component/select-names/e-select-names-text-model.c
blob: 13054eb10ebd934661d5abf8dfd84b8d8d087c79 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                                                           
                                                        














                                                                                                


                                                                                                                        

                                                                                                     



                                                                                                 
                                                                               
                                                                                   

















































                                                                                             
                                                                                           
























                                                                                  



                                                                                    

 






                                                                     
           
                                                                              
 

                                                                                         
                                                          

                                   



                                                       


                                              
                                            
                                                     

                                                       


           
                                                                                             
 





                                                                                                    
                              
                        
                                                    

                 






                                                       
                                                    

                                                       


           
                                                                                                          
 





                                                                                                    
                              
                        
                                                    

                 






                                                       
                                                          


                                                       




                                                                                       









                                                                                                    
                              
                        
                                                    

                 

                                                       

 







































































                                                                                                       


                                                                      


                                                













                                                                                                    
                          

                               

                          














                                                                                                    
                                   

                                            



                                
                       


                                                                                   



























































































                                                                                                               
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Authors: 
 *   Chris Lahey     <clahey@helixcode.com>
 *
 * Copyright (C) 2000 Helix Code, Inc.
 */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>

#include <addressbook/contact-editor/e-contact-editor.h>
#include "e-select-names-text-model.h"

/* 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_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 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()

/**
 * e_select_names_text_model_get_type:
 * @void: 
 * 
 * Registers the &ESelectNamesTextModel class if necessary, and returns the type ID
 * associated to it.
 * 
 * Return value: The type ID of the &ESelectNamesTextModel class.
 **/
GtkType
e_select_names_text_model_get_type (void)
{
    static GtkType model_type = 0;

    if (!model_type) {
        GtkTypeInfo model_info = {
            "ESelectNamesTextModel",
            sizeof (ESelectNamesTextModel),
            sizeof (ESelectNamesTextModelClass),
            (GtkClassInitFunc) e_select_names_text_model_class_init,
            (GtkObjectInitFunc) e_select_names_text_model_init,
            NULL, /* reserved_1 */
            NULL, /* reserved_2 */
            (GtkClassInitFunc) NULL
        };

        model_type = gtk_type_unique (PARENT_TYPE, &model_info);
    }

    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)
{
    GtkObjectClass *object_class;
    ETextModelClass *text_model_class;

    object_class = GTK_OBJECT_CLASS(klass);
    text_model_class = E_TEXT_MODEL_CLASS(klass);

    parent_class = gtk_type_class(PARENT_TYPE);

    gtk_object_add_arg_type ("ESelectNamesTextModel::source",
                 GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_SOURCE);

    object_class->destroy = e_select_names_text_model_destroy;
    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->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;
    text_model_class->delete        = e_select_names_text_model_delete;

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

static int
get_length(EIterator *iterator)
{
    const ESelectNamesModelData *data = e_iterator_get(iterator);
    return strlen(data->string);
}

static void
e_select_names_text_model_set_text      (ETextModel *model, const gchar *text)
{
    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);
    
    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));
}

static void
e_select_names_text_model_insert        (ETextModel *model, gint position, const gchar *text)
{
    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) {
            break;
        } else {
            position -= this_length + 1;
        }
    }
    if (!e_iterator_is_valid(iterator)) {
        gtk_object_unref(GTK_OBJECT(iterator));
        iterator = NULL;
    }
    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)
{
    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) {
            break;
        } else {
            position -= this_length + 1;
        }
    }
    if (!e_iterator_is_valid(iterator)) {
        gtk_object_unref(GTK_OBJECT(iterator));
        iterator = NULL;
    }
    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)
{
    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;
        }
    }
    if (iterator)
        gtk_object_unref(GTK_OBJECT(iterator));
}

static gint
e_select_names_text_model_obj_count (ETextModel *model)
{
    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;
    
    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;
    }

    return count;
}

static const gchar *
e_select_names_text_model_get_nth_obj (ETextModel *model, gint n, gint *len)
{
    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);

        pos += len + 1; /* advance and extra space for comma */
        ++i;
        if (data->type == E_SELECT_NAMES_MODEL_DATA_TYPE_CARD)
            --n;

        if (n >= 0)
            e_iterator_next (iterator);
    }

    if (len) {
        data = e_iterator_get (iterator);
        *len = strlen (data->string);
    }

    return e_text_model_get_text (model) + pos;
}

static void
e_select_names_text_model_activate_obj (ETextModel *model, gint n)
{
    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;

    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;

        if (n >= 0)
            e_iterator_next (iterator);
    }

    data = e_iterator_get (iterator);
    card = E_CARD (data->card);

    /* FIXME: const incorrectness here. */  
    contact_editor = e_contact_editor_new ((ECard *) card, FALSE);
    e_contact_editor_raise (contact_editor);
}

static void
e_select_names_text_model_model_changed (ESelectNamesModel     *source,
                     ESelectNamesTextModel *model)
{
    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++;
    }
    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 (stringp != string) {
        stringp --;
        *stringp = 0;
    }
    *lengthsp = -1;

    E_TEXT_MODEL_CLASS (parent_class)->set_text (E_TEXT_MODEL (model), string);
    g_free (string);
}


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

static void
e_select_names_text_model_drop_source (ESelectNamesTextModel *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;
}

/*
 * ESelectNamesTextModel lifecycle management and vcard loading/saving.
 */

static void
e_select_names_text_model_destroy (GtkObject *object)
{
    ESelectNamesTextModel *model;
    
    model = E_SELECT_NAMES_TEXT_MODEL (object);
    
    e_select_names_text_model_drop_source(model);
    g_free(model->lengths);
    
    if (GTK_OBJECT_CLASS(parent_class)->destroy)
        GTK_OBJECT_CLASS(parent_class)->destroy(object);
}


/* Set_arg handler for the model */
static void
e_select_names_text_model_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
    ESelectNamesTextModel *model;
    
    model = E_SELECT_NAMES_TEXT_MODEL (object);

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

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

    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_text_model_init:
 */
static void
e_select_names_text_model_init (ESelectNamesTextModel *model)
{
    model->source = NULL;
    model->source_changed_id = 0;
    model->lengths = NULL;
}