]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-cell-renderer-text.c
Remove spurious comment
[empathy.git] / libempathy-gtk / empathy-cell-renderer-text.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004-2007 Imendio AB
4  * Copyright (C) 2010 Collabora Ltd
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  *
21  * Authors: Mikael Hallendal <micke@imendio.com>
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include <libempathy/empathy-utils.h>
29 #include "empathy-cell-renderer-text.h"
30
31 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCellRendererText)
32 typedef struct {
33         gchar    *name;
34         TpConnectionPresenceType presence_type;
35         gchar    *status;
36         gboolean  is_group;
37
38         gboolean  is_valid;
39         gboolean  is_selected;
40
41         gchar   **types;
42
43         gboolean  compact;
44 } EmpathyCellRendererTextPriv;
45
46 static void cell_renderer_text_finalize          (GObject                     *object);
47 static void cell_renderer_text_get_property      (GObject                     *object,
48                                                   guint                        param_id,
49                                                   GValue                      *value,
50                                                   GParamSpec                  *pspec);
51 static void cell_renderer_text_set_property      (GObject                     *object,
52                                                   guint                        param_id,
53                                                   const GValue                *value,
54                                                   GParamSpec                  *pspec);
55 static void cell_renderer_text_render            (GtkCellRenderer             *cell,
56                                                   cairo_t *cr,
57                                                   GtkWidget                   *widget,
58                                                   const GdkRectangle          *background_area,
59                                                   const GdkRectangle          *cell_area,
60                                                   GtkCellRendererState         flags);
61 static void cell_renderer_text_update_text       (EmpathyCellRendererText      *cell,
62                                                   GtkWidget                   *widget,
63                                                   gboolean                     selected);
64
65 /* Properties */
66 enum {
67         PROP_0,
68         PROP_NAME,
69         PROP_PRESENCE_TYPE,
70         PROP_STATUS,
71         PROP_IS_GROUP,
72         PROP_COMPACT,
73         PROP_CLIENT_TYPES
74 };
75
76 G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
77
78 static void
79 cell_renderer_text_get_preferred_height_for_width (GtkCellRenderer *renderer,
80                                                                 GtkWidget *widget,
81                                                                 gint width,
82                                                                 gint *minimum_size,
83                                                                 gint *natural_size)
84 {
85         EmpathyCellRendererText *self = EMPATHY_CELL_RENDERER_TEXT (renderer);
86         EmpathyCellRendererTextPriv *priv = GET_PRIV (self);
87
88         /* Only update if not already valid so we get the right size. */
89         cell_renderer_text_update_text (self, widget, priv->is_selected);
90
91         GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->
92                         get_preferred_height_for_width (renderer, widget, width,
93                                         minimum_size, natural_size);
94 }
95
96
97 static void
98 empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
99 {
100         GObjectClass         *object_class;
101         GtkCellRendererClass *cell_class;
102         GParamSpec           *spec;
103
104         object_class = G_OBJECT_CLASS (klass);
105         cell_class = GTK_CELL_RENDERER_CLASS (klass);
106
107         object_class->finalize = cell_renderer_text_finalize;
108
109         object_class->get_property = cell_renderer_text_get_property;
110         object_class->set_property = cell_renderer_text_set_property;
111
112         cell_class->get_preferred_height_for_width = cell_renderer_text_get_preferred_height_for_width;
113         cell_class->render = cell_renderer_text_render;
114
115         spec = g_param_spec_string ("name", "Name", "Contact name", NULL,
116                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
117         g_object_class_install_property (object_class, PROP_NAME, spec);
118
119         spec = g_param_spec_uint ("presence-type", "TpConnectionPresenceType",
120                 "The contact's presence type",
121                 0, G_MAXUINT, /* Telepathy enum, can be extended */
122                 TP_CONNECTION_PRESENCE_TYPE_UNKNOWN,
123                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
124         g_object_class_install_property (object_class, PROP_PRESENCE_TYPE,
125                 spec);
126
127         spec = g_param_spec_string ("status", "Status message",
128                 "Contact's custom status message", NULL,
129                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
130         g_object_class_install_property (object_class, PROP_STATUS, spec);
131
132         spec = g_param_spec_boolean ("is-group", "Is group",
133                 "Whether this cell is a group", FALSE,
134                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
135         g_object_class_install_property (object_class, PROP_IS_GROUP, spec);
136
137         spec = g_param_spec_boolean ("compact", "Compact",
138                 "TRUE to show the status alongside the contact name;"
139                 "FALSE to show it on its own line",
140                 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
141         g_object_class_install_property (object_class, PROP_COMPACT, spec);
142
143         spec = g_param_spec_boxed ("client-types", "Contact client types",
144                 "Client types of the contact",
145                 G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
146         g_object_class_install_property (object_class, PROP_CLIENT_TYPES, spec);
147
148         g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
149 }
150
151 static void
152 empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
153 {
154         EmpathyCellRendererTextPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
155                 EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv);
156
157         cell->priv = priv;
158         g_object_set (cell,
159                       "ellipsize", PANGO_ELLIPSIZE_END,
160                       NULL);
161
162         priv->name = g_strdup ("");
163         priv->status = g_strdup ("");
164         priv->compact = FALSE;
165 }
166
167 static void
168 cell_renderer_text_finalize (GObject *object)
169 {
170         EmpathyCellRendererText     *cell;
171         EmpathyCellRendererTextPriv *priv;
172
173         cell = EMPATHY_CELL_RENDERER_TEXT (object);
174         priv = GET_PRIV (cell);
175
176         g_free (priv->name);
177         g_free (priv->status);
178         g_strfreev (priv->types);
179
180         (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
181 }
182
183 static void
184 cell_renderer_text_get_property (GObject    *object,
185                                  guint       param_id,
186                                  GValue     *value,
187                                  GParamSpec *pspec)
188 {
189         EmpathyCellRendererText     *cell;
190         EmpathyCellRendererTextPriv *priv;
191
192         cell = EMPATHY_CELL_RENDERER_TEXT (object);
193         priv = GET_PRIV (cell);
194
195         switch (param_id) {
196         case PROP_NAME:
197                 g_value_set_string (value, priv->name);
198                 break;
199         case PROP_PRESENCE_TYPE:
200                 g_value_set_uint (value, priv->presence_type);
201                 break;
202         case PROP_STATUS:
203                 g_value_set_string (value, priv->status);
204                 break;
205         case PROP_IS_GROUP:
206                 g_value_set_boolean (value, priv->is_group);
207                 break;
208         case PROP_COMPACT:
209                 g_value_set_boolean (value, priv->compact);
210                 break;
211         case PROP_CLIENT_TYPES:
212                 g_value_set_boxed (value, priv->types);
213                 break;
214         default:
215                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
216                 break;
217         }
218 }
219
220 static void
221 cell_renderer_text_set_property (GObject      *object,
222                                  guint         param_id,
223                                  const GValue *value,
224                                  GParamSpec   *pspec)
225 {
226         EmpathyCellRendererText     *cell;
227         EmpathyCellRendererTextPriv *priv;
228         const gchar                *str;
229
230         cell = EMPATHY_CELL_RENDERER_TEXT (object);
231         priv = GET_PRIV (cell);
232
233         switch (param_id) {
234         case PROP_NAME:
235                 g_free (priv->name);
236                 str = g_value_get_string (value);
237                 priv->name = g_strdup (str ? str : "");
238                 g_strdelimit (priv->name, "\n\r\t", ' ');
239                 priv->is_valid = FALSE;
240                 break;
241         case PROP_PRESENCE_TYPE:
242                 priv->presence_type = g_value_get_uint (value);
243                 priv->is_valid = FALSE;
244                 break;
245         case PROP_STATUS:
246                 g_free (priv->status);
247                 str = g_value_get_string (value);
248                 priv->status = g_strdup (str ? str : "");
249                 g_strdelimit (priv->status, "\n\r\t", ' ');
250                 priv->is_valid = FALSE;
251                 break;
252         case PROP_IS_GROUP:
253                 priv->is_group = g_value_get_boolean (value);
254                 priv->is_valid = FALSE;
255                 break;
256         case PROP_COMPACT:
257                 priv->compact = g_value_get_boolean (value);
258                 priv->is_valid = FALSE;
259                 break;
260         case PROP_CLIENT_TYPES:
261                 priv->types = g_value_dup_boxed (value);
262                 priv->is_valid = FALSE;
263                 break;
264         default:
265                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
266                 break;
267         }
268 }
269
270 static void
271 cell_renderer_text_render (GtkCellRenderer      *cell,
272                            cairo_t *cr,
273                            GtkWidget            *widget,
274                            const GdkRectangle   *background_area,
275                            const GdkRectangle   *cell_area,
276                            GtkCellRendererState  flags)
277 {
278         EmpathyCellRendererText *celltext;
279
280         celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
281
282         cell_renderer_text_update_text (celltext,
283                                         widget,
284                                         (flags & GTK_CELL_RENDERER_SELECTED));
285
286         (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
287                 cell, cr,
288                 widget,
289                 background_area,
290                 cell_area,
291                 flags);
292 }
293
294 static void
295 cell_renderer_text_update_text (EmpathyCellRendererText *cell,
296                                 GtkWidget              *widget,
297                                 gboolean                selected)
298 {
299         EmpathyCellRendererTextPriv *priv;
300         PangoAttrList              *attr_list;
301         PangoAttribute             *attr_color = NULL, *attr_size;
302         GtkStyle                   *style;
303         gchar                      *str;
304
305         priv = GET_PRIV (cell);
306
307         if (priv->is_valid && priv->is_selected == selected) {
308                 return;
309         }
310
311         if (priv->is_group) {
312                 g_object_set (cell,
313                               "visible", TRUE,
314                               "weight", PANGO_WEIGHT_BOLD,
315                               "text", priv->name,
316                               "attributes", NULL,
317                               "xpad", 1,
318                               "ypad", 1,
319                               NULL);
320
321                 priv->is_selected = selected;
322                 priv->is_valid = TRUE;
323                 return;
324         }
325
326         style = gtk_widget_get_style (widget);
327
328         attr_list = pango_attr_list_new ();
329
330         attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
331         attr_size->start_index = strlen (priv->name) + 1;
332         attr_size->end_index = -1;
333         pango_attr_list_insert (attr_list, attr_size);
334
335         if (!selected) {
336                 GdkColor color;
337
338                 color = style->text_aa[GTK_STATE_NORMAL];
339
340                 attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
341                 attr_color->start_index = attr_size->start_index;
342                 attr_color->end_index = -1;
343                 pango_attr_list_insert (attr_list, attr_color);
344         }
345
346         if (priv->compact) {
347                 if (EMP_STR_EMPTY (priv->status)) {
348                         str = g_strdup (priv->name);
349                 } else {
350                         str = g_strdup_printf ("%s %s", priv->name, priv->status);
351                 }
352         } else {
353                 const gchar *status = priv->status;
354                 gboolean on_a_phone = FALSE;
355
356                 if (EMP_STR_EMPTY (priv->status)) {
357                         status = empathy_presence_get_default_message (priv->presence_type);
358                 }
359
360                 if (!priv->is_group && priv->types != NULL && g_strv_length (priv->types) > 0
361                     && !tp_strdiff (priv->types[0], "phone")) {
362                         on_a_phone = TRUE;
363                         /* We want the phone black. */
364                         if (attr_color)
365                                 attr_color->start_index += 3;
366                 }
367
368                 if (status == NULL)
369                         str = g_strdup (priv->name);
370                 else
371                         str = g_strdup_printf ("%s\n%s%s", priv->name,
372                                                on_a_phone ? "☎  " : "",
373                                                status);
374         }
375
376         g_object_set (cell,
377                       "visible", TRUE,
378                       "weight", PANGO_WEIGHT_NORMAL,
379                       "text", str,
380                       "attributes", attr_list,
381                       "xpad", 0,
382                       "ypad", 1,
383                       NULL);
384
385         g_free (str);
386         pango_attr_list_unref (attr_list);
387
388         priv->is_selected = selected;
389         priv->is_valid = TRUE;
390 }
391
392 GtkCellRenderer *
393 empathy_cell_renderer_text_new (void)
394 {
395         return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);
396 }