]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-theme.c
Simplify chat theme system
[empathy.git] / libempathy-gtk / empathy-theme.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <glib/gi18n.h>
25 #include <gtk/gtk.h>
26
27 #include <libempathy/empathy-conf.h>
28 #include <libempathy/empathy-debug.h>
29 #include <libempathy/empathy-utils.h>
30 #include <libempathy/empathy-marshal.h>
31
32 #include "empathy-chat.h"
33 #include "empathy-preferences.h"
34 #include "empathy-theme.h"
35 #include "empathy-smiley-manager.h"
36
37 #define DEBUG_DOMAIN "Theme"
38
39 /* Number of seconds between timestamps when using normal mode, 5 minutes. */
40 #define TIMESTAMP_INTERVAL 300
41
42 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME, EmpathyThemePriv))
43
44 typedef struct _EmpathyThemePriv EmpathyThemePriv;
45
46 struct _EmpathyThemePriv {
47         EmpathySmileyManager *smiley_manager;
48         gboolean show_avatars;
49 };
50
51 static void         theme_finalize            (GObject            *object);
52 static void         theme_get_property        (GObject            *object,
53                                                guint               param_id,
54                                                GValue             *value,
55                                                GParamSpec         *pspec);
56 static void         theme_set_property        (GObject            *object,
57                                                guint               param_id,
58                                                const GValue       *value,
59                                                GParamSpec         *pspec);
60
61
62 G_DEFINE_TYPE (EmpathyTheme, empathy_theme, G_TYPE_OBJECT);
63
64 enum {
65         PROP_0,
66         PROP_SHOW_AVATARS
67 };
68
69 static void
70 empathy_theme_class_init (EmpathyThemeClass *class)
71 {
72         GObjectClass *object_class;
73
74         object_class = G_OBJECT_CLASS (class);
75
76         object_class->finalize     = theme_finalize;
77         object_class->get_property = theme_get_property;
78         object_class->set_property = theme_set_property;
79
80         class->update_view      = NULL;
81         class->append_message   = NULL;
82         class->append_event     = NULL;
83         class->append_timestamp = NULL;
84         class->append_spacing   = NULL;
85
86         g_object_class_install_property (object_class,
87                                          PROP_SHOW_AVATARS,
88                                          g_param_spec_boolean ("show-avatars",
89                                                                "", "",
90                                                                TRUE,
91                                                                G_PARAM_READWRITE));
92
93         g_type_class_add_private (object_class, sizeof (EmpathyThemePriv));
94 }
95
96 static void
97 empathy_theme_init (EmpathyTheme *presence)
98 {
99         EmpathyThemePriv *priv;
100
101         priv = GET_PRIV (presence);
102
103         priv->smiley_manager = empathy_smiley_manager_new ();
104 }
105
106 static void
107 theme_finalize (GObject *object)
108 {
109         EmpathyThemePriv *priv;
110
111         priv = GET_PRIV (object);
112
113         if (priv->smiley_manager) {
114                 g_object_unref (priv->smiley_manager);
115         }
116
117         (G_OBJECT_CLASS (empathy_theme_parent_class)->finalize) (object);
118 }
119
120 static void
121 theme_get_property (GObject    *object,
122                     guint       param_id,
123                     GValue     *value,
124                     GParamSpec *pspec)
125 {
126         EmpathyThemePriv *priv;
127
128         priv = GET_PRIV (object);
129
130         switch (param_id) {
131         case PROP_SHOW_AVATARS:
132                 g_value_set_boolean (value, priv->show_avatars);
133                 break;
134         default:
135                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
136                 break;
137         }
138 }
139
140 static void
141 theme_set_property (GObject      *object,
142                     guint         param_id,
143                     const GValue *value,
144                     GParamSpec   *pspec)
145 {
146         EmpathyThemePriv *priv;
147
148         priv = GET_PRIV (object);
149
150         switch (param_id) {
151         case PROP_SHOW_AVATARS:
152                 empathy_theme_set_show_avatars (EMPATHY_THEME (object),
153                                                 g_value_get_boolean (value));
154                 break;
155         default:
156                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
157                 break;
158         }
159 }
160
161 void
162 empathy_theme_maybe_append_date_and_time (EmpathyTheme        *theme,
163                                          EmpathyChatView     *view,
164                                          EmpathyMessage      *message)
165 {
166         time_t    timestamp;
167         GDate    *date, *last_date;
168         gboolean  append_date, append_time;
169
170         date = empathy_message_get_date_and_time (message, &timestamp);
171
172         last_date = g_date_new ();
173         g_date_set_time (last_date, empathy_chat_view_get_last_timestamp (view));
174
175         append_date = FALSE;
176         append_time = FALSE;
177
178         if (g_date_compare (date, last_date) > 0) {
179                 append_date = TRUE;
180                 append_time = TRUE;
181         }
182         
183         g_date_free (last_date);
184         g_date_free (date);
185
186         if (empathy_chat_view_get_last_timestamp (view) + TIMESTAMP_INTERVAL < timestamp) {
187                 append_time = TRUE;
188         }
189
190         if (append_time || append_date) {
191                 empathy_theme_append_timestamp (theme, view, message,
192                                                append_date, append_time);
193         }
194 }
195
196 void
197 empathy_theme_update_view (EmpathyTheme    *theme,
198                            EmpathyChatView *view)
199 {
200         if (!EMPATHY_THEME_GET_CLASS(theme)->update_view) {
201                 g_error ("Theme must override update_view");
202         }
203
204         return EMPATHY_THEME_GET_CLASS(theme)->update_view (theme, view);
205 }
206
207 void
208 empathy_theme_append_message (EmpathyTheme        *theme,
209                              EmpathyChatView     *view,
210                              EmpathyMessage      *message)
211 {
212         if (!EMPATHY_THEME_GET_CLASS(theme)->append_message) {
213                 g_warning ("Theme should override append_message");
214                 return;
215         }
216
217         EMPATHY_THEME_GET_CLASS(theme)->append_message (theme, view, message);
218 }
219
220 static void
221 theme_insert_text_with_emoticons (GtkTextBuffer *buf,
222                                   GtkTextIter   *iter,
223                                   const gchar   *str,
224                                   EmpathySmileyManager *smiley_manager)
225 {
226         gboolean             use_smileys = FALSE;
227         GSList              *smileys, *l;
228
229         empathy_conf_get_bool (empathy_conf_get (),
230                               EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
231                               &use_smileys);
232
233         if (!use_smileys) {
234                 gtk_text_buffer_insert (buf, iter, str, -1);
235                 return;
236         }
237
238         smileys = empathy_smiley_manager_parse (smiley_manager, str);
239         for (l = smileys; l; l = l->next) {
240                 EmpathySmiley *smiley;
241
242                 smiley = l->data;
243                 if (smiley->pixbuf) {
244                         gtk_text_buffer_insert_pixbuf (buf, iter, smiley->pixbuf);
245                 } else {
246                         gtk_text_buffer_insert (buf, iter, smiley->str, -1);
247                 }
248                 empathy_smiley_free (smiley);
249         }
250         g_slist_free (smileys);
251 }
252
253 void
254 empathy_theme_append_text (EmpathyTheme        *theme,
255                           EmpathyChatView     *view,
256                           const gchar        *body,
257                           const gchar        *tag,
258                           const gchar        *link_tag)
259 {
260         EmpathyThemePriv *priv;
261         GtkTextBuffer   *buffer;
262         GtkTextIter      start_iter, end_iter;
263         GtkTextMark     *mark;
264         GtkTextIter      iter;
265         gint             num_matches, i;
266         GArray          *start, *end;
267
268         priv = GET_PRIV (theme);
269         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
270
271         gtk_text_buffer_get_end_iter (buffer, &start_iter);
272         mark = gtk_text_buffer_create_mark (buffer, NULL, &start_iter, TRUE);
273
274         start = g_array_new (FALSE, FALSE, sizeof (gint));
275         end = g_array_new (FALSE, FALSE, sizeof (gint));
276
277         num_matches = empathy_regex_match (EMPATHY_REGEX_ALL, body, start, end);
278
279         if (num_matches == 0) {
280                 gtk_text_buffer_get_end_iter (buffer, &iter);
281                 theme_insert_text_with_emoticons (buffer, &iter, body, priv->smiley_manager);
282         } else {
283                 gint   last = 0;
284                 gint   s = 0, e = 0;
285                 gchar *tmp;
286
287                 for (i = 0; i < num_matches; i++) {
288                         s = g_array_index (start, gint, i);
289                         e = g_array_index (end, gint, i);
290
291                         if (s > last) {
292                                 tmp = empathy_substring (body, last, s);
293
294                                 gtk_text_buffer_get_end_iter (buffer, &iter);
295                                 theme_insert_text_with_emoticons (buffer,
296                                                                   &iter,
297                                                                   tmp,
298                                                                   priv->smiley_manager);
299                                 g_free (tmp);
300                         }
301
302                         tmp = empathy_substring (body, s, e);
303
304                         gtk_text_buffer_get_end_iter (buffer, &iter);
305                         if (!link_tag) {
306                                 gtk_text_buffer_insert (buffer, &iter,
307                                                         tmp, -1);
308                         } {
309                                 gtk_text_buffer_insert_with_tags_by_name (buffer,
310                                                                           &iter,
311                                                                           tmp,
312                                                                           -1,
313                                                                           link_tag,
314                                                                           "link",
315                                                                           NULL);
316                         }
317
318                         g_free (tmp);
319
320                         last = e;
321                 }
322
323                 if (e < strlen (body)) {
324                         tmp = empathy_substring (body, e, strlen (body));
325
326                         gtk_text_buffer_get_end_iter (buffer, &iter);
327                         theme_insert_text_with_emoticons (buffer,
328                                                           &iter,
329                                                           tmp,
330                                                           priv->smiley_manager);
331                         g_free (tmp);
332                 }
333         }
334
335         g_array_free (start, TRUE);
336         g_array_free (end, TRUE);
337
338         gtk_text_buffer_get_end_iter (buffer, &iter);
339         gtk_text_buffer_insert (buffer, &iter, "\n", 1);
340
341         /* Apply the style to the inserted text. */
342         gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, mark);
343         gtk_text_buffer_get_end_iter (buffer, &end_iter);
344
345         gtk_text_buffer_apply_tag_by_name (buffer,
346                                            tag,
347                                            &start_iter,
348                                            &end_iter);
349
350         gtk_text_buffer_delete_mark (buffer, mark);
351 }
352
353 void 
354 empathy_theme_append_event (EmpathyTheme        *theme,
355                            EmpathyChatView     *view,
356                            const gchar        *str)
357 {
358         if (!EMPATHY_THEME_GET_CLASS(theme)->append_event) {
359                 return;
360         }
361
362         EMPATHY_THEME_GET_CLASS(theme)->append_event (theme, view, str);
363 }
364
365 void
366 empathy_theme_append_spacing (EmpathyTheme        *theme, 
367                              EmpathyChatView     *view)
368 {
369         if (!EMPATHY_THEME_GET_CLASS(theme)->append_spacing) {
370                 return;
371         }
372
373         EMPATHY_THEME_GET_CLASS(theme)->append_spacing (theme, view);
374 }
375
376
377 void 
378 empathy_theme_append_timestamp (EmpathyTheme        *theme,
379                                EmpathyChatView     *view,
380                                EmpathyMessage      *message,
381                                gboolean            show_date,
382                                gboolean            show_time)
383 {
384         if (!EMPATHY_THEME_GET_CLASS(theme)->append_timestamp) {
385                 return;
386         }
387
388         EMPATHY_THEME_GET_CLASS(theme)->append_timestamp (theme, view,
389                                                          message, show_date,
390                                                          show_time);
391 }
392
393 gboolean
394 empathy_theme_get_show_avatars (EmpathyTheme *theme)
395 {
396         EmpathyThemePriv *priv;
397
398         g_return_val_if_fail (EMPATHY_IS_THEME (theme), FALSE);
399
400         priv = GET_PRIV (theme);
401
402         return priv->show_avatars;
403 }
404
405 void
406 empathy_theme_set_show_avatars (EmpathyTheme *theme, gboolean show)
407 {
408         EmpathyThemePriv *priv;
409
410         g_return_if_fail (EMPATHY_IS_THEME (theme));
411
412         priv = GET_PRIV (theme);
413
414         priv->show_avatars = show;
415
416         g_object_notify (G_OBJECT (theme), "show-avatars");
417 }
418