]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-theme.c
Don't forget to show the contact widget in some places
[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-lib.h>
25 #include <gtk/gtk.h>
26
27 #include <libempathy/empathy-utils.h>
28
29 #include "empathy-chat.h"
30 #include "empathy-conf.h"
31 #include "empathy-theme.h"
32 #include "empathy-smiley-manager.h"
33
34 /* Number of seconds between timestamps when using normal mode, 5 minutes. */
35 #define TIMESTAMP_INTERVAL 300
36
37 #define SCHEMES "(https?|ftps?|nntp|news|javascript|about|ghelp|apt|telnet|"\
38                 "file|webcal|mailto)"
39 #define BODY "([^\\ ]+)"
40 #define END_BODY "([^\\ ]*[^,;\?><()\\ \"\\.])"
41 #define URI_REGEX "("SCHEMES"://"END_BODY")" \
42                   "|((mailto:)?"BODY"@"BODY"\\."END_BODY")"\
43                   "|((www|ftp)\\."END_BODY")"
44 static GRegex *uri_regex = NULL;
45
46 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTheme)
47
48 typedef struct {
49         EmpathySmileyManager *smiley_manager;
50         gboolean show_avatars;
51 } EmpathyThemePriv;
52
53 static void         theme_finalize            (GObject            *object);
54 static void         theme_get_property        (GObject            *object,
55                                                guint               param_id,
56                                                GValue             *value,
57                                                GParamSpec         *pspec);
58 static void         theme_set_property        (GObject            *object,
59                                                guint               param_id,
60                                                const GValue       *value,
61                                                GParamSpec         *pspec);
62
63
64 G_DEFINE_TYPE (EmpathyTheme, empathy_theme, G_TYPE_OBJECT);
65
66 enum {
67         PROP_0,
68         PROP_SHOW_AVATARS
69 };
70
71 static void
72 empathy_theme_class_init (EmpathyThemeClass *class)
73 {
74         GObjectClass *object_class;
75
76         object_class = G_OBJECT_CLASS (class);
77
78         object_class->finalize     = theme_finalize;
79         object_class->get_property = theme_get_property;
80         object_class->set_property = theme_set_property;
81
82         class->update_view      = NULL;
83         class->append_message   = NULL;
84         class->append_event     = NULL;
85         class->append_timestamp = NULL;
86         class->append_spacing   = NULL;
87
88         g_object_class_install_property (object_class,
89                                          PROP_SHOW_AVATARS,
90                                          g_param_spec_boolean ("show-avatars",
91                                                                "", "",
92                                                                TRUE,
93                                                                G_PARAM_READWRITE));
94
95         g_type_class_add_private (object_class, sizeof (EmpathyThemePriv));
96 }
97
98 static void
99 empathy_theme_init (EmpathyTheme *theme)
100 {
101         EmpathyThemePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (theme,
102                 EMPATHY_TYPE_THEME, EmpathyThemePriv);
103
104         theme->priv = priv;
105         priv->smiley_manager = empathy_smiley_manager_dup_singleton ();
106 }
107
108 static void
109 theme_finalize (GObject *object)
110 {
111         EmpathyThemePriv *priv;
112
113         priv = GET_PRIV (object);
114
115         if (priv->smiley_manager) {
116                 g_object_unref (priv->smiley_manager);
117         }
118
119         (G_OBJECT_CLASS (empathy_theme_parent_class)->finalize) (object);
120 }
121
122 static void
123 theme_get_property (GObject    *object,
124                     guint       param_id,
125                     GValue     *value,
126                     GParamSpec *pspec)
127 {
128         EmpathyThemePriv *priv;
129
130         priv = GET_PRIV (object);
131
132         switch (param_id) {
133         case PROP_SHOW_AVATARS:
134                 g_value_set_boolean (value, priv->show_avatars);
135                 break;
136         default:
137                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
138                 break;
139         }
140 }
141
142 static void
143 theme_set_property (GObject      *object,
144                     guint         param_id,
145                     const GValue *value,
146                     GParamSpec   *pspec)
147 {
148         EmpathyThemePriv *priv;
149
150         priv = GET_PRIV (object);
151
152         switch (param_id) {
153         case PROP_SHOW_AVATARS:
154                 empathy_theme_set_show_avatars (EMPATHY_THEME (object),
155                                                 g_value_get_boolean (value));
156                 break;
157         default:
158                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
159                 break;
160         }
161 }
162
163 void
164 empathy_theme_maybe_append_date_and_time (EmpathyTheme        *theme,
165                                          EmpathyChatView     *view,
166                                          EmpathyMessage      *message)
167 {
168         time_t    timestamp;
169         GDate    *date, *last_date;
170         gboolean  append_date, append_time;
171
172         date = empathy_message_get_date_and_time (message, &timestamp);
173
174         last_date = g_date_new ();
175         g_date_set_time_t (last_date, empathy_chat_view_get_last_timestamp (view));
176
177         append_date = FALSE;
178         append_time = FALSE;
179
180         if (g_date_compare (date, last_date) > 0) {
181                 append_date = TRUE;
182                 append_time = TRUE;
183         }
184         
185         g_date_free (last_date);
186         g_date_free (date);
187
188         if (empathy_chat_view_get_last_timestamp (view) + TIMESTAMP_INTERVAL < timestamp) {
189                 append_time = TRUE;
190         }
191
192         if (append_time || append_date) {
193                 empathy_theme_append_timestamp (theme, view, message,
194                                                append_date, append_time);
195         }
196 }
197
198 void
199 empathy_theme_update_view (EmpathyTheme    *theme,
200                            EmpathyChatView *view)
201 {
202         if (!EMPATHY_THEME_GET_CLASS(theme)->update_view) {
203                 g_error ("Theme must override update_view");
204         }
205
206         EMPATHY_THEME_GET_CLASS(theme)->update_view (theme, view);
207 }
208
209 void
210 empathy_theme_append_message (EmpathyTheme        *theme,
211                              EmpathyChatView     *view,
212                              EmpathyMessage      *message)
213 {
214         if (!EMPATHY_THEME_GET_CLASS(theme)->append_message) {
215                 g_warning ("Theme should override append_message");
216                 return;
217         }
218
219         EMPATHY_THEME_GET_CLASS(theme)->append_message (theme, view, message);
220 }
221
222 static void
223 theme_insert_text_with_emoticons (GtkTextBuffer *buf,
224                                   GtkTextIter   *iter,
225                                   const gchar   *str,
226                                   EmpathySmileyManager *smiley_manager)
227 {
228         gboolean             use_smileys = FALSE;
229         GSList              *smileys, *l;
230
231         empathy_conf_get_bool (empathy_conf_get (),
232                               EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
233                               &use_smileys);
234
235         if (!use_smileys) {
236                 gtk_text_buffer_insert (buf, iter, str, -1);
237                 return;
238         }
239
240         smileys = empathy_smiley_manager_parse (smiley_manager, str);
241         for (l = smileys; l; l = l->next) {
242                 EmpathySmiley *smiley;
243
244                 smiley = l->data;
245                 if (smiley->pixbuf) {
246                         gtk_text_buffer_insert_pixbuf (buf, iter, smiley->pixbuf);
247                 } else {
248                         gtk_text_buffer_insert (buf, iter, smiley->str, -1);
249                 }
250                 empathy_smiley_free (smiley);
251         }
252         g_slist_free (smileys);
253 }
254
255 void
256 empathy_theme_append_text (EmpathyTheme        *theme,
257                           EmpathyChatView     *view,
258                           const gchar        *body,
259                           const gchar        *tag,
260                           const gchar        *link_tag)
261 {
262         EmpathyThemePriv *priv;
263         GtkTextBuffer   *buffer;
264         GtkTextIter      start_iter, end_iter;
265         GtkTextMark     *mark;
266         GtkTextIter      iter;
267         GMatchInfo      *match_info;
268         gboolean         match;
269         gint             last = 0;
270         gint             s = 0, e = 0;
271         gchar           *tmp;
272
273         priv = GET_PRIV (theme);
274         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
275
276         gtk_text_buffer_get_end_iter (buffer, &start_iter);
277         mark = gtk_text_buffer_create_mark (buffer, NULL, &start_iter, TRUE);
278
279         if (!uri_regex) {
280                 uri_regex = g_regex_new (URI_REGEX, 0, 0, NULL);
281         }
282
283         for (match = g_regex_match (uri_regex, body, 0, &match_info); match;
284              match = g_match_info_next (match_info, NULL)) {
285                 if (!g_match_info_fetch_pos (match_info, 0, &s, &e))
286                         continue;
287
288                 if (s > last) {
289                         tmp = empathy_substring (body, last, s);
290
291                         gtk_text_buffer_get_end_iter (buffer, &iter);
292                         theme_insert_text_with_emoticons (buffer,
293                                                           &iter,
294                                                           tmp,
295                                                           priv->smiley_manager);
296                         g_free (tmp);
297                 }
298
299                 tmp = empathy_substring (body, s, e);
300
301                 gtk_text_buffer_get_end_iter (buffer, &iter);
302                 if (!link_tag) {
303                         gtk_text_buffer_insert (buffer, &iter,
304                                                 tmp, -1);
305                 } else {
306                         gtk_text_buffer_insert_with_tags_by_name (buffer,
307                                                                   &iter,
308                                                                   tmp,
309                                                                   -1,
310                                                                   link_tag,
311                                                                   "link",
312                                                                   NULL);
313                 }
314
315                 g_free (tmp);
316                 last = e;
317         }
318         g_match_info_free (match_info);
319
320         if (last < strlen (body)) {
321                 gtk_text_buffer_get_end_iter (buffer, &iter);
322                 theme_insert_text_with_emoticons (buffer,
323                                                   &iter,
324                                                   body + last,
325                                                   priv->smiley_manager);
326         }
327
328         gtk_text_buffer_get_end_iter (buffer, &iter);
329         gtk_text_buffer_insert (buffer, &iter, "\n", 1);
330
331         /* Apply the style to the inserted text. */
332         gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, mark);
333         gtk_text_buffer_get_end_iter (buffer, &end_iter);
334
335         gtk_text_buffer_apply_tag_by_name (buffer,
336                                            tag,
337                                            &start_iter,
338                                            &end_iter);
339
340         gtk_text_buffer_delete_mark (buffer, mark);
341 }
342
343 void 
344 empathy_theme_append_event (EmpathyTheme        *theme,
345                            EmpathyChatView     *view,
346                            const gchar        *str)
347 {
348         if (!EMPATHY_THEME_GET_CLASS(theme)->append_event) {
349                 return;
350         }
351
352         EMPATHY_THEME_GET_CLASS(theme)->append_event (theme, view, str);
353 }
354
355 void
356 empathy_theme_append_spacing (EmpathyTheme        *theme, 
357                              EmpathyChatView     *view)
358 {
359         if (!EMPATHY_THEME_GET_CLASS(theme)->append_spacing) {
360                 return;
361         }
362
363         EMPATHY_THEME_GET_CLASS(theme)->append_spacing (theme, view);
364 }
365
366
367 void 
368 empathy_theme_append_timestamp (EmpathyTheme        *theme,
369                                EmpathyChatView     *view,
370                                EmpathyMessage      *message,
371                                gboolean            show_date,
372                                gboolean            show_time)
373 {
374         if (!EMPATHY_THEME_GET_CLASS(theme)->append_timestamp) {
375                 return;
376         }
377
378         EMPATHY_THEME_GET_CLASS(theme)->append_timestamp (theme, view,
379                                                          message, show_date,
380                                                          show_time);
381 }
382
383 gboolean
384 empathy_theme_get_show_avatars (EmpathyTheme *theme)
385 {
386         EmpathyThemePriv *priv;
387
388         g_return_val_if_fail (EMPATHY_IS_THEME (theme), FALSE);
389
390         priv = GET_PRIV (theme);
391
392         return priv->show_avatars;
393 }
394
395 void
396 empathy_theme_set_show_avatars (EmpathyTheme *theme, gboolean show)
397 {
398         EmpathyThemePriv *priv;
399
400         g_return_if_fail (EMPATHY_IS_THEME (theme));
401
402         priv = GET_PRIV (theme);
403
404         priv->show_avatars = show;
405
406         g_object_notify (G_OBJECT (theme), "show-avatars");
407 }
408