]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-cell-renderer-text.c
CellRendererText: Use G_PARAM_STATIC_STRINGS
[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         gboolean  compact;
42 } EmpathyCellRendererTextPriv;
43
44 static void cell_renderer_text_finalize          (GObject                     *object);
45 static void cell_renderer_text_get_property      (GObject                     *object,
46                                                   guint                        param_id,
47                                                   GValue                      *value,
48                                                   GParamSpec                  *pspec);
49 static void cell_renderer_text_set_property      (GObject                     *object,
50                                                   guint                        param_id,
51                                                   const GValue                *value,
52                                                   GParamSpec                  *pspec);
53 static void cell_renderer_text_get_size          (GtkCellRenderer             *cell,
54                                                   GtkWidget                   *widget,
55                                                   GdkRectangle                *cell_area,
56                                                   gint                        *x_offset,
57                                                   gint                        *y_offset,
58                                                   gint                        *width,
59                                                   gint                        *height);
60 static void cell_renderer_text_render            (GtkCellRenderer             *cell,
61                                                   GdkDrawable                 *window,
62                                                   GtkWidget                   *widget,
63                                                   GdkRectangle                *background_area,
64                                                   GdkRectangle                *cell_area,
65                                                   GdkRectangle                *expose_area,
66                                                   GtkCellRendererState         flags);
67 static void cell_renderer_text_update_text       (EmpathyCellRendererText      *cell,
68                                                   GtkWidget                   *widget,
69                                                   gboolean                     selected);
70
71 /* Properties */
72 enum {
73         PROP_0,
74         PROP_NAME,
75         PROP_PRESENCE_TYPE,
76         PROP_STATUS,
77         PROP_IS_GROUP,
78         PROP_COMPACT
79 };
80
81 G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
82
83 static void
84 empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
85 {
86         GObjectClass         *object_class;
87         GtkCellRendererClass *cell_class;
88         GParamSpec           *spec;
89
90         object_class = G_OBJECT_CLASS (klass);
91         cell_class = GTK_CELL_RENDERER_CLASS (klass);
92
93         object_class->finalize = cell_renderer_text_finalize;
94
95         object_class->get_property = cell_renderer_text_get_property;
96         object_class->set_property = cell_renderer_text_set_property;
97
98         cell_class->get_size = cell_renderer_text_get_size;
99         cell_class->render = cell_renderer_text_render;
100
101         spec = g_param_spec_string ("name", "Name", "Contact name", NULL,
102                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
103         g_object_class_install_property (object_class, PROP_NAME, spec);
104
105         spec = g_param_spec_uint ("presence-type", "TpConnectionPresenceType",
106                 "The contact's presence type",
107                 0, G_MAXUINT, /* Telepathy enum, can be extended */
108                 TP_CONNECTION_PRESENCE_TYPE_UNKNOWN,
109                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
110         g_object_class_install_property (object_class, PROP_PRESENCE_TYPE,
111                 spec);
112
113         spec = g_param_spec_string ("status", "Status message",
114                 "Contact's custom status message", NULL,
115                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
116         g_object_class_install_property (object_class, PROP_STATUS, spec);
117
118         spec = g_param_spec_boolean ("is-group", "Is group",
119                 "Whether this cell is a group", FALSE,
120                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
121         g_object_class_install_property (object_class, PROP_IS_GROUP, spec);
122
123         spec = g_param_spec_boolean ("compact", "Compact",
124                 "TRUE to show the status alongside the contact name;"
125                 "FALSE to show it on its own line",
126                 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
127         g_object_class_install_property (object_class, PROP_COMPACT, spec);
128
129         g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
130 }
131
132 static void
133 empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
134 {
135         EmpathyCellRendererTextPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
136                 EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv);
137
138         cell->priv = priv;
139         g_object_set (cell,
140                       "ellipsize", PANGO_ELLIPSIZE_END,
141                       NULL);
142
143         priv->name = g_strdup ("");
144         priv->status = g_strdup ("");
145         priv->compact = FALSE;
146 }
147
148 static void
149 cell_renderer_text_finalize (GObject *object)
150 {
151         EmpathyCellRendererText     *cell;
152         EmpathyCellRendererTextPriv *priv;
153
154         cell = EMPATHY_CELL_RENDERER_TEXT (object);
155         priv = GET_PRIV (cell);
156
157         g_free (priv->name);
158         g_free (priv->status);
159
160         (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
161 }
162
163 static void
164 cell_renderer_text_get_property (GObject    *object,
165                                  guint       param_id,
166                                  GValue     *value,
167                                  GParamSpec *pspec)
168 {
169         EmpathyCellRendererText     *cell;
170         EmpathyCellRendererTextPriv *priv;
171
172         cell = EMPATHY_CELL_RENDERER_TEXT (object);
173         priv = GET_PRIV (cell);
174
175         switch (param_id) {
176         case PROP_NAME:
177                 g_value_set_string (value, priv->name);
178                 break;
179         case PROP_PRESENCE_TYPE:
180                 g_value_set_uint (value, priv->presence_type);
181                 break;
182         case PROP_STATUS:
183                 g_value_set_string (value, priv->status);
184                 break;
185         case PROP_IS_GROUP:
186                 g_value_set_boolean (value, priv->is_group);
187                 break;
188         case PROP_COMPACT:
189                 g_value_set_boolean (value, priv->compact);
190                 break;
191         default:
192                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
193                 break;
194         }
195 }
196
197 static void
198 cell_renderer_text_set_property (GObject      *object,
199                                  guint         param_id,
200                                  const GValue *value,
201                                  GParamSpec   *pspec)
202 {
203         EmpathyCellRendererText     *cell;
204         EmpathyCellRendererTextPriv *priv;
205         const gchar                *str;
206
207         cell = EMPATHY_CELL_RENDERER_TEXT (object);
208         priv = GET_PRIV (cell);
209
210         switch (param_id) {
211         case PROP_NAME:
212                 g_free (priv->name);
213                 str = g_value_get_string (value);
214                 priv->name = g_strdup (str ? str : "");
215                 g_strdelimit (priv->name, "\n\r\t", ' ');
216                 priv->is_valid = FALSE;
217                 break;
218         case PROP_PRESENCE_TYPE:
219                 priv->presence_type = g_value_get_uint (value);
220                 priv->is_valid = FALSE;
221                 break;
222         case PROP_STATUS:
223                 g_free (priv->status);
224                 str = g_value_get_string (value);
225                 priv->status = g_strdup (str ? str : "");
226                 g_strdelimit (priv->status, "\n\r\t", ' ');
227                 priv->is_valid = FALSE;
228                 break;
229         case PROP_IS_GROUP:
230                 priv->is_group = g_value_get_boolean (value);
231                 priv->is_valid = FALSE;
232                 break;
233         case PROP_COMPACT:
234                 priv->compact = g_value_get_boolean (value);
235                 priv->is_valid = FALSE;
236                 break;
237         default:
238                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
239                 break;
240         }
241 }
242
243 static void
244 cell_renderer_text_get_size (GtkCellRenderer *cell,
245                              GtkWidget       *widget,
246                              GdkRectangle    *cell_area,
247                              gint            *x_offset,
248                              gint            *y_offset,
249                              gint            *width,
250                              gint            *height)
251 {
252         EmpathyCellRendererText     *celltext;
253         EmpathyCellRendererTextPriv *priv;
254
255         celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
256         priv = GET_PRIV (cell);
257
258         /* Only update if not already valid so we get the right size. */
259         cell_renderer_text_update_text (celltext, widget, priv->is_selected);
260
261         (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->get_size) (cell, widget,
262                                                                                       cell_area,
263                                                                                       x_offset, y_offset,
264                                                                                       width, height);
265 }
266
267 static void
268 cell_renderer_text_render (GtkCellRenderer      *cell,
269                            GdkWindow            *window,
270                            GtkWidget            *widget,
271                            GdkRectangle         *background_area,
272                            GdkRectangle         *cell_area,
273                            GdkRectangle         *expose_area,
274                            GtkCellRendererState  flags)
275 {
276         EmpathyCellRendererText *celltext;
277
278         celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
279
280         cell_renderer_text_update_text (celltext,
281                                         widget,
282                                         (flags & GTK_CELL_RENDERER_SELECTED));
283
284         (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
285                 cell, window,
286                 widget,
287                 background_area,
288                 cell_area,
289                 expose_area, flags);
290 }
291
292 static void
293 cell_renderer_text_update_text (EmpathyCellRendererText *cell,
294                                 GtkWidget              *widget,
295                                 gboolean                selected)
296 {
297         EmpathyCellRendererTextPriv *priv;
298         PangoAttrList              *attr_list;
299         PangoAttribute             *attr_color, *attr_size;
300         GtkStyle                   *style;
301         gchar                      *str;
302
303         priv = GET_PRIV (cell);
304
305         if (priv->is_valid && priv->is_selected == selected) {
306                 return;
307         }
308
309         if (priv->is_group) {
310                 g_object_set (cell,
311                               "visible", TRUE,
312                               "weight", PANGO_WEIGHT_BOLD,
313                               "text", priv->name,
314                               "attributes", NULL,
315                               "xpad", 1,
316                               "ypad", 1,
317                               NULL);
318
319                 priv->is_selected = selected;
320                 priv->is_valid = TRUE;
321                 return;
322         }
323
324         style = gtk_widget_get_style (widget);
325
326         attr_list = pango_attr_list_new ();
327
328         attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
329         attr_size->start_index = strlen (priv->name) + 1;
330         attr_size->end_index = -1;
331         pango_attr_list_insert (attr_list, attr_size);
332
333         if (!selected) {
334                 GdkColor color;
335
336                 color = style->text_aa[GTK_STATE_NORMAL];
337
338                 attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
339                 attr_color->start_index = attr_size->start_index;
340                 attr_color->end_index = -1;
341                 pango_attr_list_insert (attr_list, attr_color);
342         }
343
344         if (priv->compact) {
345                 if (EMP_STR_EMPTY (priv->status)) {
346                         str = g_strdup (priv->name);
347                 } else {
348                         str = g_strdup_printf ("%s %s", priv->name, priv->status);
349                 }
350         } else {
351                 const gchar *status = priv->status;
352
353                 if (EMP_STR_EMPTY (priv->status)) {
354                         status = empathy_presence_get_default_message (priv->presence_type);
355                 }
356
357                 str = g_strdup_printf ("%s\n%s", priv->name, status);
358         }
359
360         g_object_set (cell,
361                       "visible", TRUE,
362                       "weight", PANGO_WEIGHT_NORMAL,
363                       "text", str,
364                       "attributes", attr_list,
365                       "xpad", 0,
366                       "ypad", 1,
367                       NULL);
368
369         g_free (str);
370         pango_attr_list_unref (attr_list);
371
372         priv->is_selected = selected;
373         priv->is_valid = TRUE;
374 }
375
376 GtkCellRenderer *
377 empathy_cell_renderer_text_new (void)
378 {
379         return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);
380 }