aboutsummaryrefslogblamecommitdiffstats
path: root/libempathy-gtk/empathy-cell-renderer-text.c
blob: 22c0e05b31b1418f397483ac14fd4ff147676e40 (plain) (tree)
1
2
3
4


                                                                           
                                   












                                                                     


                                                               






                                                
                                     
                                       
 

                                                                     
                       
                                               





                              

                        
                          
                              
 








                                                                                        
                                                                                    
                                                              
                                                                                      

                                                                                               
                                                                                      
                                                                                     






                                                                                         
                           

                      

                         

  
                                                                                                 

           


















                                                                                   
                                                                           


                                           
                                   








                                                                     
                                                                                                       

                                                       
                                                                         
                                                            

                                                                        



                                                                              
                                                            



                                                                          

                                                            

                                                                          


                                                            

                                                                            


                                                                     
                                                                   
                                                                           
 




                                                                                
                                                                                      


           
                                                               
 

                                                                              
 
                          





                                                       
                              




                                             

                                          
 
                                                   



                               
                                 
 
                                                                                      







                                                      

                                          
 
                                                   





                                                       


                                                              





                                                            

                                                           
                      


                                                       











                                                                            

                                          

                                        
                                                   









                                                         



                                                               










                                                             

                                                            

                                       



                                                        






                                                                            
                                                      
                                       
                                                        

                                                                 

                                                       
                                          
 
                                                     




                                                                              
                                                                                     
                         


                                
                       


           
                                                              


                                                                 
                                          
                                              
                                                                  



























                                                              



                                                                                                   






                                                                                            
                                                                 



                                                               





                                                                                  
                
                                                   
                                            




                                                                                            
                                                                                             






                                                               


                                                    


                                                                         


















                                                    
                                     
 
                                                                    
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2004-2007 Imendio AB
 * Copyright (C) 2010 Collabora Ltd
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 *
 * Authors: Mikael Hallendal <micke@imendio.com>
 */

#include "config.h"

#include <string.h>

#include <libempathy/empathy-utils.h>
#include "empathy-cell-renderer-text.h"

#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCellRendererText)
typedef struct {
    gchar    *name;
    TpConnectionPresenceType presence_type;
    gchar    *status;
    gboolean  is_group;

    gboolean  is_valid;
    gboolean  is_selected;

    gchar   **types;

    gboolean  compact;
} EmpathyCellRendererTextPriv;

static void cell_renderer_text_finalize          (GObject                     *object);
static void cell_renderer_text_get_property      (GObject                     *object,
                          guint                        param_id,
                          GValue                      *value,
                          GParamSpec                  *pspec);
static void cell_renderer_text_set_property      (GObject                     *object,
                          guint                        param_id,
                          const GValue                *value,
                          GParamSpec                  *pspec);
static void cell_renderer_text_render            (GtkCellRenderer             *cell,
                          cairo_t *cr,
                          GtkWidget                   *widget,
                          const GdkRectangle          *background_area,
                          const GdkRectangle          *cell_area,
                          GtkCellRendererState         flags);
static void cell_renderer_text_update_text       (EmpathyCellRendererText      *cell,
                          GtkWidget                   *widget,
                          gboolean                     selected);

/* Properties */
enum {
    PROP_0,
    PROP_NAME,
    PROP_PRESENCE_TYPE,
    PROP_STATUS,
    PROP_IS_GROUP,
    PROP_COMPACT,
    PROP_CLIENT_TYPES
};

G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);

static void
cell_renderer_text_get_preferred_height_for_width (GtkCellRenderer *renderer,
                                GtkWidget *widget,
                                gint width,
                                gint *minimum_size,
                                gint *natural_size)
{
    EmpathyCellRendererText *self = EMPATHY_CELL_RENDERER_TEXT (renderer);
    EmpathyCellRendererTextPriv *priv = GET_PRIV (self);

    /* Only update if not already valid so we get the right size. */
    cell_renderer_text_update_text (self, widget, priv->is_selected);

    GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->
            get_preferred_height_for_width (renderer, widget, width,
                    minimum_size, natural_size);
}


static void
empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
{
    GObjectClass         *object_class;
    GtkCellRendererClass *cell_class;
    GParamSpec           *spec;

    object_class = G_OBJECT_CLASS (klass);
    cell_class = GTK_CELL_RENDERER_CLASS (klass);

    object_class->finalize = cell_renderer_text_finalize;

    object_class->get_property = cell_renderer_text_get_property;
    object_class->set_property = cell_renderer_text_set_property;

    cell_class->get_preferred_height_for_width = cell_renderer_text_get_preferred_height_for_width;
    cell_class->render = cell_renderer_text_render;

    spec = g_param_spec_string ("name", "Name", "Contact name", NULL,
        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_NAME, spec);

    spec = g_param_spec_uint ("presence-type", "TpConnectionPresenceType",
        "The contact's presence type",
        0, G_MAXUINT, /* Telepathy enum, can be extended */
        TP_CONNECTION_PRESENCE_TYPE_UNKNOWN,
        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_PRESENCE_TYPE,
        spec);

    spec = g_param_spec_string ("status", "Status message",
        "Contact's custom status message", NULL,
        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_STATUS, spec);

    spec = g_param_spec_boolean ("is-group", "Is group",
        "Whether this cell is a group", FALSE,
        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_IS_GROUP, spec);

    spec = g_param_spec_boolean ("compact", "Compact",
        "TRUE to show the status alongside the contact name;"
        "FALSE to show it on its own line",
        FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_COMPACT, spec);

    spec = g_param_spec_boxed ("client-types", "Contact client types",
        "Client types of the contact",
        G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_CLIENT_TYPES, spec);

    g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
}

static void
empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
{
    EmpathyCellRendererTextPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
        EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv);

    cell->priv = priv;
    g_object_set (cell,
              "ellipsize", PANGO_ELLIPSIZE_END,
              NULL);

    priv->name = g_strdup ("");
    priv->status = g_strdup ("");
    priv->compact = FALSE;
}

static void
cell_renderer_text_finalize (GObject *object)
{
    EmpathyCellRendererText     *cell;
    EmpathyCellRendererTextPriv *priv;

    cell = EMPATHY_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    g_free (priv->name);
    g_free (priv->status);
    g_strfreev (priv->types);

    (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
}

static void
cell_renderer_text_get_property (GObject    *object,
                 guint       param_id,
                 GValue     *value,
                 GParamSpec *pspec)
{
    EmpathyCellRendererText     *cell;
    EmpathyCellRendererTextPriv *priv;

    cell = EMPATHY_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    switch (param_id) {
    case PROP_NAME:
        g_value_set_string (value, priv->name);
        break;
    case PROP_PRESENCE_TYPE:
        g_value_set_uint (value, priv->presence_type);
        break;
    case PROP_STATUS:
        g_value_set_string (value, priv->status);
        break;
    case PROP_IS_GROUP:
        g_value_set_boolean (value, priv->is_group);
        break;
    case PROP_COMPACT:
        g_value_set_boolean (value, priv->compact);
        break;
    case PROP_CLIENT_TYPES:
        g_value_set_boxed (value, priv->types);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
        break;
    }
}

static void
cell_renderer_text_set_property (GObject      *object,
                 guint         param_id,
                 const GValue *value,
                 GParamSpec   *pspec)
{
    EmpathyCellRendererText     *cell;
    EmpathyCellRendererTextPriv *priv;
    const gchar                *str;

    cell = EMPATHY_CELL_RENDERER_TEXT (object);
    priv = GET_PRIV (cell);

    switch (param_id) {
    case PROP_NAME:
        g_free (priv->name);
        str = g_value_get_string (value);
        priv->name = g_strdup (str ? str : "");
        g_strdelimit (priv->name, "\n\r\t", ' ');
        priv->is_valid = FALSE;
        break;
    case PROP_PRESENCE_TYPE:
        priv->presence_type = g_value_get_uint (value);
        priv->is_valid = FALSE;
        break;
    case PROP_STATUS:
        g_free (priv->status);
        str = g_value_get_string (value);
        priv->status = g_strdup (str ? str : "");
        g_strdelimit (priv->status, "\n\r\t", ' ');
        priv->is_valid = FALSE;
        break;
    case PROP_IS_GROUP:
        priv->is_group = g_value_get_boolean (value);
        priv->is_valid = FALSE;
        break;
    case PROP_COMPACT:
        priv->compact = g_value_get_boolean (value);
        priv->is_valid = FALSE;
        break;
    case PROP_CLIENT_TYPES:
        priv->types = g_value_dup_boxed (value);
        priv->is_valid = FALSE;
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
        break;
    }
}

static void
cell_renderer_text_render (GtkCellRenderer      *cell,
               cairo_t *cr,
               GtkWidget            *widget,
               const GdkRectangle   *background_area,
               const GdkRectangle   *cell_area,
               GtkCellRendererState  flags)
{
    EmpathyCellRendererText *celltext;

    celltext = EMPATHY_CELL_RENDERER_TEXT (cell);

    cell_renderer_text_update_text (celltext,
                    widget,
                    (flags & GTK_CELL_RENDERER_SELECTED));

    (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
        cell, cr,
        widget,
        background_area,
        cell_area,
        flags);
}

static void
cell_renderer_text_update_text (EmpathyCellRendererText *cell,
                GtkWidget              *widget,
                gboolean                selected)
{
    EmpathyCellRendererTextPriv *priv;
    PangoAttrList              *attr_list;
    PangoAttribute             *attr_color = NULL, *attr_size;
    GtkStyle                   *style;
    gchar                      *str;

    priv = GET_PRIV (cell);

    if (priv->is_valid && priv->is_selected == selected) {
        return;
    }

    if (priv->is_group) {
        g_object_set (cell,
                  "visible", TRUE,
                  "weight", PANGO_WEIGHT_BOLD,
                  "text", priv->name,
                  "attributes", NULL,
                  "xpad", 1,
                  "ypad", 1,
                  NULL);

        priv->is_selected = selected;
        priv->is_valid = TRUE;
        return;
    }

    style = gtk_widget_get_style (widget);

    attr_list = pango_attr_list_new ();

    attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
    attr_size->start_index = strlen (priv->name) + 1;
    attr_size->end_index = -1;
    pango_attr_list_insert (attr_list, attr_size);

    if (!selected) {
        GdkColor color;

        color = style->text_aa[GTK_STATE_NORMAL];

        attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
        attr_color->start_index = attr_size->start_index;
        attr_color->end_index = -1;
        pango_attr_list_insert (attr_list, attr_color);
    }

    if (priv->compact) {
        if (EMP_STR_EMPTY (priv->status)) {
            str = g_strdup (priv->name);
        } else {
            str = g_strdup_printf ("%s %s", priv->name, priv->status);
        }
    } else {
        const gchar *status = priv->status;
        gboolean on_a_phone = FALSE;

        if (EMP_STR_EMPTY (priv->status)) {
            status = empathy_presence_get_default_message (priv->presence_type);
        }

        if (!priv->is_group && priv->types != NULL && g_strv_length (priv->types) > 0
            && !tp_strdiff (priv->types[0], "phone")) {
            on_a_phone = TRUE;
            /* We want the phone black. */
            if (attr_color)
                attr_color->start_index += 3;
        }

        if (status == NULL)
            str = g_strdup (priv->name);
        else
            str = g_strdup_printf ("%s\n%s%s", priv->name,
                           on_a_phone ? "☎  " : "",
                           status);
    }

    g_object_set (cell,
              "visible", TRUE,
              "weight", PANGO_WEIGHT_NORMAL,
              "text", str,
              "attributes", attr_list,
              "xpad", 0,
              "ypad", 1,
              NULL);

    g_free (str);
    pango_attr_list_unref (attr_list);

    priv->is_selected = selected;
    priv->is_valid = TRUE;
}

GtkCellRenderer *
empathy_cell_renderer_text_new (void)
{
    return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);
}