aboutsummaryrefslogblamecommitdiffstats
path: root/addressbook/gui/widgets/e-addressbook-reflow-adapter.c
blob: 48ed73bb253333818be48ab0f9521e8266d59229 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                                                                           











                                                                    
                                                                             


                                                        
 
                    
                   

      
                   
 
                       

                                         
                         
 
                       
                          
                                                 
 



                                                                                     
                                          
                                 


                         

                                                                                       

  


            
               
                    

                      
                  



                   
                     


                   
                                          
 




                                     
           
                                                 


                                                               
                                                   


                                                 
                                                   


                                                 
                                                   


                                                 
                                                  


                                                
                                                   


                                                 
                                                  


                                                
 


                                    
                                   

                                    
 

                                             



                           
           

                                 
 
                    
 
                                                 
 
                                                            
 


                      
           
                                     
 
                                                                                   

                               


           

                                         



                                                                    
           

                                     
                                                                                

                                                               
                                                               

 
                                                                     
           


                                             
 
                                                                                
                                                               
                            

                       
                                                                                         
                            
                    
 


                                                                     
                                                            
                                                                   
                        
 

                                                                           
 
                                                                                    

                                 
                                                        
                                        

                                               
 
                                                                                          
 
                                                                         





                                                                
                                




                                
                                



                      















                                                                                        












                                                                          





                         
           



                                           
 
                                                                                
                                                               
                                      

                            
                               

              

                                                                                         
 
                                           

                                                         











                                                                                                 



                                          


                                                                             
                                                           



                                          
                 
                             
                                  
                             
                                 
                         
         

 
           


                                                       


                         



                                       



                       







                                                                   
                        


                                                
 
                                                                                


                                                               




                                                                           
 


                                                          
 


                                                            
 



                    


                                               
 
                                                                                

                                                               



                                                                           

 
           
                                         


                                                   
 



                                         


           
                                          

                                                   
 
                                          
                                  
 
                       


                                                          
            
                                                                  
 


           
                                         

                                                   




                                                                      
                                        
                                                  




                                                          
                                         
                                                   






                                                               
                                        

                                                  








                                                                     
                                          
                                            

                                              
 
                                                                                   

                                                               
                              
                         



                                                             
                      
                        



                                                            
                      
                           



                                                                

                      
                                                                               




                      
                                          
                                            

                                            
 
                                                                                   

                                                               
                              
                           


                                               

                      
                          


                                               

                      
                             


                                               

                      

                                                        
                      
                
                                                                               




                      
                                                                               
 

                                              
 

                                                                  
 
                                              

                                                              
                                                    
 








                                                                            


























































                                                                               


           
                                                                      
 
                                                                           



                                                                           
                                                                 


                                                               
























                                                       


              
                                                           


                                      
                                                                    


                                                           
                                   

 

                                                                             
                                                     


                                                               
                                                                    
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>

#include <glib/gi18n.h>
#include "e-addressbook-reflow-adapter.h"
#include "e-addressbook-model.h"
#include "eab-gui-util.h"

#include "e-minicard.h"
#include <e-util/e-util.h>
#include "addressbook/printing/e-contact-print.h"

#define E_ADDRESSBOOK_REFLOW_ADAPTER_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE \
    ((obj), E_TYPE_ADDRESSBOOK_REFLOW_ADAPTER, EAddressbookReflowAdapterPrivate))

struct _EAddressbookReflowAdapterPrivate {
    EAddressbookModel *model;

    gboolean loading;

    gint create_contact_id, remove_contact_id, modify_contact_id, model_changed_id;
    gint search_started_id, search_result_id;
};

#define d(x)

enum {
    PROP_0,
    PROP_CLIENT,
    PROP_QUERY,
    PROP_EDITABLE,
    PROP_MODEL
};

enum {
    DRAG_BEGIN,
    OPEN_CONTACT,
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = {0, };

G_DEFINE_TYPE (
    EAddressbookReflowAdapter,
    e_addressbook_reflow_adapter,
    E_TYPE_REFLOW_MODEL)

static void
unlink_model (EAddressbookReflowAdapter *adapter)
{
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    if (priv->model && priv->create_contact_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->create_contact_id);
    if (priv->model && priv->remove_contact_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->remove_contact_id);
    if (priv->model && priv->modify_contact_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->modify_contact_id);
    if (priv->model && priv->model_changed_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->model_changed_id);
    if (priv->model && priv->search_started_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->search_started_id);
    if (priv->model && priv->search_result_id)
        g_signal_handler_disconnect (
            priv->model,
            priv->search_result_id);

    priv->create_contact_id = 0;
    priv->remove_contact_id = 0;
    priv->modify_contact_id = 0;
    priv->model_changed_id = 0;
    priv->search_started_id = 0;
    priv->search_result_id = 0;

    if (priv->model)
        g_object_unref (priv->model);

    priv->model = NULL;
}

static gint
text_height (PangoLayout *layout,
             const gchar *text)
{
    gint height;

    pango_layout_set_text (layout, text, -1);

    pango_layout_get_pixel_size (layout, NULL, &height);

    return height;
}

static void
addressbook_dispose (GObject *object)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (object);

    unlink_model (adapter);
}

static void
addressbook_set_width (EReflowModel *erm,
                       gint width)
{
}

/* This function returns the number of items in our EReflowModel. */
static gint
addressbook_count (EReflowModel *erm)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    return e_addressbook_model_contact_count (priv->model);
}

/* This function returns the height of the minicontact in question */
static gint
addressbook_height (EReflowModel *erm,
                    gint i,
                    GnomeCanvasGroup *parent)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;
    EContactField field;
    gint count = 0;
    gchar *string;
    EContact *contact = (EContact *) e_addressbook_model_contact_at (priv->model, i);
    PangoLayout *layout;
    gint height;

    layout = gtk_widget_create_pango_layout (
        GTK_WIDGET (GNOME_CANVAS_ITEM (parent)->canvas), "");

    string = e_contact_get (contact, E_CONTACT_FILE_AS);
    height = text_height (layout, string ? string : "") + 10.0;
    g_free (string);

    for (field = E_CONTACT_FULL_NAME;
         field != E_CONTACT_LAST_SIMPLE_STRING && count < 5; field++) {

        if (field == E_CONTACT_FAMILY_NAME || field == E_CONTACT_GIVEN_NAME)
            continue;

        string = e_contact_get (contact, field);
        if (string && *string) {
            gint this_height;
            gint field_text_height;

            this_height = text_height (layout, e_contact_pretty_name (field));

            field_text_height = text_height (layout, string);
            if (this_height < field_text_height)
                this_height = field_text_height;

            this_height += 3;

            height += this_height;
            count++;
        }
        g_free (string);
    }
    height += 2;

    g_object_unref (layout);

    return height;
}

static GHashTable *
addressbook_create_cmp_cache (EReflowModel *erm)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;
    GHashTable *cmp_cache;
    gint ii, count;

    count = e_reflow_model_count (erm);

    if (priv->loading || count <= 0)
        return NULL;

    cmp_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);

    for (ii = 0; ii < count; ii++) {
        EContact *contact;

        contact  = (EContact *)
            e_addressbook_model_contact_at (priv->model, ii);
        if (contact != NULL) {
            const gchar *file_as;

            file_as = e_contact_get_const (
                contact, E_CONTACT_FILE_AS);
            if (file_as != NULL)
                g_hash_table_insert (
                    cmp_cache, GINT_TO_POINTER (ii),
                    g_utf8_collate_key (file_as, -1));
        }
    }

    return cmp_cache;
}

static gint
addressbook_compare (EReflowModel *erm,
                     gint n1,
                     gint n2,
                     GHashTable *cmp_cache)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;
    EContact *contact1, *contact2;

    if (priv->loading) {
        return n1 - n2;
    }
    else {
        contact1 = (EContact *) e_addressbook_model_contact_at (priv->model, n1);
        contact2 = (EContact *) e_addressbook_model_contact_at (priv->model, n2);

        if (contact1 && contact2) {
            const gchar *file_as1, *file_as2;
            const gchar *uid1, *uid2;

            if (cmp_cache) {
                file_as1 = g_hash_table_lookup (cmp_cache, GINT_TO_POINTER (n1));
                file_as2 = g_hash_table_lookup (cmp_cache, GINT_TO_POINTER (n2));
                if (file_as1 && file_as2)
                    return strcmp (file_as1, file_as2);
            } else {
                file_as1 = e_contact_get_const (contact1, E_CONTACT_FILE_AS);
                file_as2 = e_contact_get_const (contact2, E_CONTACT_FILE_AS);
                if (file_as1 && file_as2)
                    return g_utf8_collate (file_as1, file_as2);
            }
            if (file_as1)
                return -1;
            if (file_as2)
                return 1;
            uid1 = e_contact_get_const (contact1, E_CONTACT_UID);
            uid2 = e_contact_get_const (contact2, E_CONTACT_UID);
            if (uid1 && uid2)
                return strcmp (uid1, uid2);
            if (uid1)
                return -1;
            if (uid2)
                return 1;
        }
        if (contact1)
            return -1;
        if (contact2)
            return 1;
        return 0;
    }
}

static gint
adapter_drag_begin (EMinicard *card,
                    GdkEvent *event,
                    EAddressbookReflowAdapter *adapter)
{
    gint ret_val = 0;

    g_signal_emit (
        adapter,
        signals[DRAG_BEGIN], 0,
        event, &ret_val);

    return ret_val;
}

static void
adapter_open_contact (EMinicard *card,
                      EContact *contact,
                      EAddressbookReflowAdapter *adapter)
{
    g_signal_emit (adapter, signals[OPEN_CONTACT], 0, contact);
}

static GnomeCanvasItem *
addressbook_incarnate (EReflowModel *erm,
                       gint i,
                       GnomeCanvasGroup *parent)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;
    GnomeCanvasItem *item;

    item = gnome_canvas_item_new (
        parent, e_minicard_get_type (),
        "contact", e_addressbook_model_contact_at (priv->model, i),
        "editable", e_addressbook_model_get_editable (priv->model),
        NULL);

    g_signal_connect (
        item, "drag_begin",
        G_CALLBACK (adapter_drag_begin), adapter);

    g_signal_connect (
        item, "open-contact",
        G_CALLBACK (adapter_open_contact), adapter);

    return item;
}

static void
addressbook_reincarnate (EReflowModel *erm,
                         gint i,
                         GnomeCanvasItem *item)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (erm);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    gnome_canvas_item_set (
        item,
        "contact", e_addressbook_model_contact_at (priv->model, i),
        NULL);
}

static void
create_contact (EAddressbookModel *model,
                gint index,
                gint count,
                EAddressbookReflowAdapter *adapter)
{
    e_reflow_model_items_inserted (
        E_REFLOW_MODEL (adapter),
        index,
        count);
}

static void
remove_contacts (EAddressbookModel *model,
                gpointer data,
                EAddressbookReflowAdapter *adapter)
{
    GArray *indices = (GArray *) data;
    gint count = indices->len;

    if (count == 1)
        e_reflow_model_item_removed (
            E_REFLOW_MODEL (adapter),
            g_array_index (indices, gint, 0));
    else
        e_reflow_model_changed (E_REFLOW_MODEL (adapter));

}

static void
modify_contact (EAddressbookModel *model,
                gint index,
                EAddressbookReflowAdapter *adapter)
{
    e_reflow_model_item_changed (E_REFLOW_MODEL (adapter), index);
}

static void
model_changed (EAddressbookModel *model,
               EAddressbookReflowAdapter *adapter)
{
    e_reflow_model_changed (E_REFLOW_MODEL (adapter));
}

static void
search_started (EAddressbookModel *model,
                EAddressbookReflowAdapter *adapter)
{
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    priv->loading = TRUE;
}

static void
search_result (EAddressbookModel *model,
               const GError *error,
               EAddressbookReflowAdapter *adapter)
{
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    priv->loading = FALSE;

    e_reflow_model_comparison_changed (E_REFLOW_MODEL (adapter));
}

static void
addressbook_set_property (GObject *object,
                          guint property_id,
                          const GValue *value,
                          GParamSpec *pspec)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (object);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    switch (property_id) {
    case PROP_CLIENT:
        g_object_set (
            priv->model,
            "client", g_value_get_object (value),
            NULL);
        break;
    case PROP_QUERY:
        g_object_set (
            priv->model,
            "query", g_value_get_string (value),
            NULL);
        break;
    case PROP_EDITABLE:
        g_object_set (
            priv->model,
            "editable", g_value_get_boolean (value),
            NULL);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        break;
    }
}

static void
addressbook_get_property (GObject *object,
                          guint property_id,
                          GValue *value,
                          GParamSpec *pspec)
{
    EAddressbookReflowAdapter *adapter = E_ADDRESSBOOK_REFLOW_ADAPTER (object);
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    switch (property_id) {
    case PROP_CLIENT: {
        g_object_get_property (
            G_OBJECT (priv->model),
            "client", value);
        break;
    }
    case PROP_QUERY: {
        g_object_get_property (
            G_OBJECT (priv->model),
            "query", value);
        break;
    }
    case PROP_EDITABLE: {
        g_object_get_property (
            G_OBJECT (priv->model),
            "editable", value);
        break;
    }
    case PROP_MODEL:
        g_value_set_object (value, priv->model);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        break;
    }
}

static void
e_addressbook_reflow_adapter_class_init (EAddressbookReflowAdapterClass *class)
{
    GObjectClass *object_class;
    EReflowModelClass *reflow_model_class;

    g_type_class_add_private (
        class, sizeof (EAddressbookReflowAdapterPrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = addressbook_set_property;
    object_class->get_property = addressbook_get_property;
    object_class->dispose = addressbook_dispose;

    reflow_model_class = E_REFLOW_MODEL_CLASS (class);
    reflow_model_class->set_width = addressbook_set_width;
    reflow_model_class->count = addressbook_count;
    reflow_model_class->height = addressbook_height;
    reflow_model_class->create_cmp_cache = addressbook_create_cmp_cache;
    reflow_model_class->compare = addressbook_compare;
    reflow_model_class->incarnate = addressbook_incarnate;
    reflow_model_class->reincarnate = addressbook_reincarnate;

    g_object_class_install_property (
        object_class,
        PROP_CLIENT,
        g_param_spec_object (
            "client",
            "EBookClient",
            NULL,
            E_TYPE_BOOK_CLIENT,
            G_PARAM_READWRITE));

    g_object_class_install_property (
        object_class,
        PROP_QUERY,
        g_param_spec_string (
            "query",
            "Query",
            NULL,
            NULL,
            G_PARAM_READWRITE));

    g_object_class_install_property (
        object_class,
        PROP_EDITABLE,
        g_param_spec_boolean (
            "editable",
            "Editable",
            NULL,
            FALSE,
            G_PARAM_READWRITE));

    g_object_class_install_property (
        object_class,
        PROP_MODEL,
        g_param_spec_object (
            "model",
            "Model",
            NULL,
            E_TYPE_ADDRESSBOOK_MODEL,
            G_PARAM_READABLE));

    signals[DRAG_BEGIN] = g_signal_new (
        "drag_begin",
        G_OBJECT_CLASS_TYPE (object_class),
        G_SIGNAL_RUN_LAST,
        G_STRUCT_OFFSET (EAddressbookReflowAdapterClass, drag_begin),
        NULL, NULL,
        e_marshal_INT__POINTER,
        G_TYPE_INT, 1,
        G_TYPE_POINTER);

    signals[OPEN_CONTACT] = g_signal_new (
        "open-contact",
        G_OBJECT_CLASS_TYPE (object_class),
        G_SIGNAL_RUN_LAST,
        G_STRUCT_OFFSET (EAddressbookReflowAdapterClass, open_contact),
        NULL, NULL,
        g_cclosure_marshal_VOID__OBJECT,
        G_TYPE_NONE, 1,
        E_TYPE_CONTACT);
}

static void
e_addressbook_reflow_adapter_init (EAddressbookReflowAdapter *adapter)
{
    adapter->priv = E_ADDRESSBOOK_REFLOW_ADAPTER_GET_PRIVATE (adapter);
}

void
e_addressbook_reflow_adapter_construct (EAddressbookReflowAdapter *adapter,
                                        EAddressbookModel *model)
{
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    priv->model = g_object_ref (model);

    priv->create_contact_id = g_signal_connect (
        priv->model, "contact_added",
        G_CALLBACK (create_contact), adapter);

    priv->remove_contact_id = g_signal_connect (
        priv->model, "contacts_removed",
        G_CALLBACK (remove_contacts), adapter);

    priv->modify_contact_id = g_signal_connect (
        priv->model, "contact_changed",
        G_CALLBACK (modify_contact), adapter);

    priv->model_changed_id = g_signal_connect (
        priv->model, "model_changed",
        G_CALLBACK (model_changed), adapter);

    priv->search_started_id = g_signal_connect (
        priv->model, "search_started",
        G_CALLBACK (search_started), adapter);

    priv->search_result_id = g_signal_connect (
        priv->model, "search_result",
        G_CALLBACK (search_result), adapter);
}

EReflowModel *
e_addressbook_reflow_adapter_new (EAddressbookModel *model)
{
    EAddressbookReflowAdapter *et;

    et = g_object_new (E_TYPE_ADDRESSBOOK_REFLOW_ADAPTER, NULL);

    e_addressbook_reflow_adapter_construct (et, model);

    return E_REFLOW_MODEL (et);
}

EContact *
e_addressbook_reflow_adapter_get_contact (EAddressbookReflowAdapter *adapter,
                                          gint index)
{
    EAddressbookReflowAdapterPrivate *priv = adapter->priv;

    return e_addressbook_model_get_contact (priv->model, index);
}