Updated Traditional Chinese translation(Hong Kong and Taiwan)
[empathy-mirror.git] / libempathy-gtk / empathy-cell-renderer-text.c
blobd52abb4851fcc434b25be04cec0cedcc8e0fcadc
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
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.
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.
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
21 * Authors: Mikael Hallendal <micke@imendio.com>
24 #include "config.h"
26 #include <string.h>
28 #include <libempathy/empathy-utils.h>
29 #include "empathy-cell-renderer-text.h"
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;
38 gboolean is_valid;
39 gboolean is_selected;
41 gchar **types;
43 gboolean compact;
44 } EmpathyCellRendererTextPriv;
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);
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
76 G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
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)
85 EmpathyCellRendererText *self = EMPATHY_CELL_RENDERER_TEXT (renderer);
86 EmpathyCellRendererTextPriv *priv = GET_PRIV (self);
88 /* Only update if not already valid so we get the right size. */
89 cell_renderer_text_update_text (self, widget, priv->is_selected);
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);
97 static void
98 empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
100 GObjectClass *object_class;
101 GtkCellRendererClass *cell_class;
102 GParamSpec *spec;
104 object_class = G_OBJECT_CLASS (klass);
105 cell_class = GTK_CELL_RENDERER_CLASS (klass);
107 object_class->finalize = cell_renderer_text_finalize;
109 object_class->get_property = cell_renderer_text_get_property;
110 object_class->set_property = cell_renderer_text_set_property;
112 cell_class->get_preferred_height_for_width = cell_renderer_text_get_preferred_height_for_width;
113 cell_class->render = cell_renderer_text_render;
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);
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);
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);
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);
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);
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);
148 g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
151 static void
152 empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
154 EmpathyCellRendererTextPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
155 EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv);
157 cell->priv = priv;
158 g_object_set (cell,
159 "ellipsize", PANGO_ELLIPSIZE_END,
160 NULL);
162 priv->name = g_strdup ("");
163 priv->status = g_strdup ("");
164 priv->compact = FALSE;
167 static void
168 cell_renderer_text_finalize (GObject *object)
170 EmpathyCellRendererText *cell;
171 EmpathyCellRendererTextPriv *priv;
173 cell = EMPATHY_CELL_RENDERER_TEXT (object);
174 priv = GET_PRIV (cell);
176 g_free (priv->name);
177 g_free (priv->status);
178 g_strfreev (priv->types);
180 (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
183 static void
184 cell_renderer_text_get_property (GObject *object,
185 guint param_id,
186 GValue *value,
187 GParamSpec *pspec)
189 EmpathyCellRendererText *cell;
190 EmpathyCellRendererTextPriv *priv;
192 cell = EMPATHY_CELL_RENDERER_TEXT (object);
193 priv = GET_PRIV (cell);
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;
220 static void
221 cell_renderer_text_set_property (GObject *object,
222 guint param_id,
223 const GValue *value,
224 GParamSpec *pspec)
226 EmpathyCellRendererText *cell;
227 EmpathyCellRendererTextPriv *priv;
228 const gchar *str;
230 cell = EMPATHY_CELL_RENDERER_TEXT (object);
231 priv = GET_PRIV (cell);
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 g_strfreev (priv->types);
262 priv->types = g_value_dup_boxed (value);
263 priv->is_valid = FALSE;
264 break;
265 default:
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
267 break;
271 static void
272 cell_renderer_text_render (GtkCellRenderer *cell,
273 cairo_t *cr,
274 GtkWidget *widget,
275 const GdkRectangle *background_area,
276 const GdkRectangle *cell_area,
277 GtkCellRendererState flags)
279 EmpathyCellRendererText *celltext;
281 celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
283 cell_renderer_text_update_text (celltext,
284 widget,
285 (flags & GTK_CELL_RENDERER_SELECTED));
287 (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
288 cell, cr,
289 widget,
290 background_area,
291 cell_area,
292 flags);
295 static void
296 cell_renderer_text_update_text (EmpathyCellRendererText *cell,
297 GtkWidget *widget,
298 gboolean selected)
300 EmpathyCellRendererTextPriv *priv;
301 const PangoFontDescription *font_desc;
302 PangoAttrList *attr_list;
303 PangoAttribute *attr_color = NULL, *attr_size;
304 GtkStyleContext *style;
305 gchar *str;
306 gint font_size;
308 priv = GET_PRIV (cell);
310 if (priv->is_valid && priv->is_selected == selected) {
311 return;
314 if (priv->is_group) {
315 g_object_set (cell,
316 "visible", TRUE,
317 "weight", PANGO_WEIGHT_BOLD,
318 "text", priv->name,
319 "attributes", NULL,
320 "xpad", 1,
321 "ypad", 1,
322 NULL);
324 priv->is_selected = selected;
325 priv->is_valid = TRUE;
326 return;
329 style = gtk_widget_get_style_context (widget);
331 attr_list = pango_attr_list_new ();
333 font_desc = gtk_style_context_get_font (style, GTK_STATE_FLAG_NORMAL);
334 font_size = pango_font_description_get_size (font_desc);
335 attr_size = pango_attr_size_new (font_size / 1.2);
336 attr_size->start_index = strlen (priv->name) + 1;
337 attr_size->end_index = -1;
338 pango_attr_list_insert (attr_list, attr_size);
340 if (!selected) {
341 GdkRGBA color;
343 gtk_style_context_get_color (style, 0, &color);
345 attr_color = pango_attr_foreground_new (color.red * 0xffff,
346 color.green * 0xffff,
347 color.blue * 0xffff);
348 attr_color->start_index = attr_size->start_index;
349 attr_color->end_index = -1;
350 pango_attr_list_insert (attr_list, attr_color);
353 if (priv->compact) {
354 if (EMP_STR_EMPTY (priv->status)) {
355 str = g_strdup (priv->name);
356 } else {
357 str = g_strdup_printf ("%s %s", priv->name, priv->status);
359 } else {
360 const gchar *status = priv->status;
361 gboolean on_a_phone = FALSE;
363 if (EMP_STR_EMPTY (priv->status)) {
364 status = empathy_presence_get_default_message (priv->presence_type);
367 if (!priv->is_group && priv->types != NULL && g_strv_length (priv->types) > 0
368 && !tp_strdiff (priv->types[0], "phone")) {
369 on_a_phone = TRUE;
370 /* We want the phone black. */
371 if (attr_color)
372 attr_color->start_index += 3;
375 if (status == NULL)
376 str = g_strdup (priv->name);
377 else
378 str = g_strdup_printf ("%s\n%s%s", priv->name,
379 on_a_phone ? "☎ " : "",
380 status);
383 g_object_set (cell,
384 "visible", TRUE,
385 "weight", PANGO_WEIGHT_NORMAL,
386 "text", str,
387 "attributes", attr_list,
388 "xpad", 0,
389 "ypad", 1,
390 NULL);
392 g_free (str);
393 pango_attr_list_unref (attr_list);
395 priv->is_selected = selected;
396 priv->is_valid = TRUE;
399 GtkCellRenderer *
400 empathy_cell_renderer_text_new (void)
402 return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);