1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Imendio AB
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.
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.
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.
25 #include <glib/gi18n.h>
28 #include "empathy-ui-utils.h"
29 #include "empathy-theme-boxes.h"
31 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
32 #include <libempathy/empathy-debug.h>
35 #define HEADER_PADDING 2
37 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_THEME_BOXES, EmpathyThemeBoxesPriv))
39 typedef struct _EmpathyThemeBoxesPriv EmpathyThemeBoxesPriv;
41 struct _EmpathyThemeBoxesPriv {
42 gchar *header_foreground;
43 gchar *header_background;
44 gchar *header_line_background;
45 gchar *text_foreground;
46 gchar *text_background;
47 gchar *action_foreground;
48 gchar *highlight_foreground;
49 gchar *time_foreground;
50 gchar *event_foreground;
51 gchar *invite_foreground;
52 gchar *link_foreground;
55 static void theme_boxes_finalize (GObject *object);
56 static void theme_boxes_get_property (GObject *object,
60 static void theme_boxes_set_property (GObject *object,
64 static void theme_boxes_define_theme_tags (EmpathyTheme *theme,
65 EmpathyChatView *view);
66 static void theme_boxes_update_view (EmpathyTheme *theme,
67 EmpathyChatView *view);
68 static void theme_boxes_append_message (EmpathyTheme *theme,
69 EmpathyChatView *view,
70 EmpathyMessage *message);
71 static void theme_boxes_append_event (EmpathyTheme *theme,
72 EmpathyChatView *view,
74 static void theme_boxes_append_timestamp (EmpathyTheme *theme,
75 EmpathyChatView *view,
76 EmpathyMessage *message,
79 static void theme_boxes_append_spacing (EmpathyTheme *theme,
80 EmpathyChatView *view);
84 PROP_HEADER_FOREGROUND,
85 PROP_HEADER_BACKGROUND,
86 PROP_HEADER_LINE_BACKGROUND,
89 PROP_ACTION_FOREGROUND,
90 PROP_HIGHLIGHT_FOREGROUND,
92 PROP_EVENT_FOREGROUND,
93 PROP_INVITE_FOREGROUND,
102 G_DEFINE_TYPE (EmpathyThemeBoxes, empathy_theme_boxes, EMPATHY_TYPE_THEME);
105 empathy_theme_boxes_class_init (EmpathyThemeBoxesClass *class)
107 GObjectClass *object_class;
108 EmpathyThemeClass *theme_class;
110 object_class = G_OBJECT_CLASS (class);
111 theme_class = EMPATHY_THEME_CLASS (class);
113 object_class->finalize = theme_boxes_finalize;
114 object_class->get_property = theme_boxes_get_property;
115 object_class->set_property = theme_boxes_set_property;
117 theme_class->update_view = theme_boxes_update_view;
118 theme_class->append_message = theme_boxes_append_message;
119 theme_class->append_event = theme_boxes_append_event;
120 theme_class->append_timestamp = theme_boxes_append_timestamp;
121 theme_class->append_spacing = theme_boxes_append_spacing;
123 g_object_class_install_property (object_class,
124 PROP_HEADER_FOREGROUND,
125 g_param_spec_string ("header-foreground",
131 g_object_class_install_property (object_class,
132 PROP_HEADER_BACKGROUND,
133 g_param_spec_string ("header-background",
139 g_object_class_install_property (object_class,
140 PROP_HEADER_LINE_BACKGROUND,
141 g_param_spec_string ("header-line-background",
148 g_object_class_install_property (object_class,
149 PROP_TEXT_FOREGROUND,
150 g_param_spec_string ("text-foreground",
156 g_object_class_install_property (object_class,
157 PROP_TEXT_BACKGROUND,
158 g_param_spec_string ("text-background",
164 g_object_class_install_property (object_class,
165 PROP_ACTION_FOREGROUND,
166 g_param_spec_string ("action-foreground",
172 g_object_class_install_property (object_class,
173 PROP_HIGHLIGHT_FOREGROUND,
174 g_param_spec_string ("highlight-foreground",
180 g_object_class_install_property (object_class,
181 PROP_TIME_FOREGROUND,
182 g_param_spec_string ("time-foreground",
188 g_object_class_install_property (object_class,
189 PROP_EVENT_FOREGROUND,
190 g_param_spec_string ("event-foreground",
196 g_object_class_install_property (object_class,
197 PROP_INVITE_FOREGROUND,
198 g_param_spec_string ("invite-foreground",
204 g_object_class_install_property (object_class,
205 PROP_LINK_FOREGROUND,
206 g_param_spec_string ("link-foreground",
212 g_type_class_add_private (object_class, sizeof (EmpathyThemeBoxesPriv));
216 empathy_theme_boxes_init (EmpathyThemeBoxes *theme)
218 EmpathyThemeBoxesPriv *priv;
220 priv = GET_PRIV (theme);
224 theme_boxes_finalize (GObject *object)
226 EmpathyThemeBoxesPriv *priv;
228 priv = GET_PRIV (object);
230 g_free (priv->header_foreground);
231 g_free (priv->header_background);
232 g_free (priv->header_line_background);
233 g_free (priv->text_foreground);
234 g_free (priv->text_background);
235 g_free (priv->action_foreground);
236 g_free (priv->highlight_foreground);
237 g_free (priv->time_foreground);
238 g_free (priv->event_foreground);
239 g_free (priv->invite_foreground);
240 g_free (priv->link_foreground);
242 (G_OBJECT_CLASS (empathy_theme_boxes_parent_class)->finalize) (object);
246 theme_boxes_get_property (GObject *object,
251 EmpathyThemeBoxesPriv *priv;
253 priv = GET_PRIV (object);
256 case PROP_HEADER_FOREGROUND:
257 g_value_set_string (value, priv->header_foreground);
259 case PROP_HEADER_BACKGROUND:
260 g_value_set_string (value, priv->header_background);
262 case PROP_HEADER_LINE_BACKGROUND:
263 g_value_set_string (value, priv->header_line_background);
265 case PROP_TEXT_FOREGROUND:
266 g_value_set_string (value, priv->text_foreground);
268 case PROP_TEXT_BACKGROUND:
269 g_value_set_string (value, priv->text_background);
271 case PROP_ACTION_FOREGROUND:
272 g_value_set_string (value, priv->action_foreground);
274 case PROP_HIGHLIGHT_FOREGROUND:
275 g_value_set_string (value, priv->highlight_foreground);
277 case PROP_TIME_FOREGROUND:
278 g_value_set_string (value, priv->time_foreground);
280 case PROP_EVENT_FOREGROUND:
281 g_value_set_string (value, priv->event_foreground);
283 case PROP_INVITE_FOREGROUND:
284 g_value_set_string (value, priv->invite_foreground);
286 case PROP_LINK_FOREGROUND:
287 g_value_set_string (value, priv->link_foreground);
290 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
295 theme_boxes_set_property (GObject *object,
300 EmpathyThemeBoxesPriv *priv;
302 priv = GET_PRIV (object);
305 case PROP_HEADER_FOREGROUND:
306 g_free (priv->header_foreground);
307 priv->header_foreground = g_value_dup_string (value);
308 g_object_notify (object, "header-foreground");
310 case PROP_HEADER_BACKGROUND:
311 g_free (priv->header_background);
312 priv->header_background = g_value_dup_string (value);
313 g_object_notify (object, "header-background");
315 case PROP_HEADER_LINE_BACKGROUND:
316 g_free (priv->header_line_background);
317 priv->header_line_background = g_value_dup_string (value);
318 g_object_notify (object, "header-line_background");
320 case PROP_TEXT_FOREGROUND:
321 g_free (priv->text_foreground);
322 priv->text_foreground = g_value_dup_string (value);
323 g_object_notify (object, "text-foreground");
325 case PROP_TEXT_BACKGROUND:
326 g_free (priv->text_background);
327 priv->text_background = g_value_dup_string (value);
328 g_object_notify (object, "text-background");
330 case PROP_ACTION_FOREGROUND:
331 g_free (priv->action_foreground);
332 priv->action_foreground = g_value_dup_string (value);
333 g_object_notify (object, "action-foreground");
335 case PROP_HIGHLIGHT_FOREGROUND:
336 g_free (priv->highlight_foreground);
337 priv->highlight_foreground = g_value_dup_string (value);
338 g_object_notify (object, "highlight-foreground");
340 case PROP_TIME_FOREGROUND:
341 g_free (priv->time_foreground);
342 priv->time_foreground = g_value_dup_string (value);
343 g_object_notify (object, "time-foreground");
345 case PROP_EVENT_FOREGROUND:
346 g_free (priv->event_foreground);
347 priv->event_foreground = g_value_dup_string (value);
348 g_object_notify (object, "event-foreground");
350 case PROP_INVITE_FOREGROUND:
351 g_free (priv->invite_foreground);
352 priv->invite_foreground = g_value_dup_string (value);
353 g_object_notify (object, "invite-foreground");
355 case PROP_LINK_FOREGROUND:
356 g_free (priv->link_foreground);
357 priv->link_foreground = g_value_dup_string (value);
358 g_object_notify (object, "link-foreground");
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
367 theme_boxes_define_theme_tags (EmpathyTheme *theme, EmpathyChatView *view)
369 EmpathyThemeBoxesPriv *priv;
370 GtkTextBuffer *buffer;
373 priv = GET_PRIV (theme);
375 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
377 empathy_text_buffer_tag_set (buffer, "fancy-spacing",
379 "pixels-above-lines", 8,
382 tag = empathy_text_buffer_tag_set (buffer, "fancy-header",
383 "weight", PANGO_WEIGHT_BOLD,
384 "pixels-above-lines", HEADER_PADDING,
385 "pixels-below-lines", HEADER_PADDING,
387 if (priv->header_foreground) {
389 "foreground", priv->header_foreground,
390 "paragraph-background", priv->header_background,
394 tag = empathy_text_buffer_tag_set (buffer, "fancy-header-line",
397 if (priv->header_line_background) {
399 "paragraph-background", priv->header_line_background,
403 tag = empathy_text_buffer_tag_set (buffer, "fancy-body",
404 "pixels-above-lines", 4,
406 if (priv->text_background) {
408 "paragraph-background", priv->text_background,
412 if (priv->text_foreground) {
414 "foreground", priv->text_foreground,
418 tag = empathy_text_buffer_tag_set (buffer, "fancy-action",
419 "style", PANGO_STYLE_ITALIC,
420 "pixels-above-lines", 4,
423 if (priv->text_background) {
425 "paragraph-background", priv->text_background,
429 if (priv->action_foreground) {
431 "foreground", priv->action_foreground,
435 tag = empathy_text_buffer_tag_set (buffer, "fancy-highlight",
436 "weight", PANGO_WEIGHT_BOLD,
437 "pixels-above-lines", 4,
439 if (priv->text_background) {
441 "paragraph-background", priv->text_background,
446 if (priv->highlight_foreground) {
448 "foreground", priv->highlight_foreground,
452 tag = empathy_text_buffer_tag_set (buffer, "fancy-time",
453 "justification", GTK_JUSTIFY_CENTER,
455 if (priv->time_foreground) {
457 "foreground", priv->time_foreground,
461 tag = empathy_text_buffer_tag_set (buffer, "fancy-event",
462 "justification", GTK_JUSTIFY_LEFT,
464 if (priv->event_foreground) {
466 "foreground", priv->event_foreground,
470 tag = empathy_text_buffer_tag_set (buffer, "invite", NULL);
471 if (priv->invite_foreground) {
473 "foreground", priv->invite_foreground,
477 tag = empathy_text_buffer_tag_set (buffer, "fancy-link",
478 "underline", PANGO_UNDERLINE_SINGLE,
480 if (priv->link_foreground) {
482 "foreground", priv->link_foreground,
488 theme_boxes_update_view (EmpathyTheme *theme, EmpathyChatView *view)
490 EmpathyThemeBoxesPriv *priv;
492 g_return_if_fail (EMPATHY_IS_THEME_BOXES (theme));
493 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
495 priv = GET_PRIV (theme);
497 theme_boxes_define_theme_tags (theme, view);
499 empathy_chat_view_set_margin (view, MARGIN);
503 table_size_allocate_cb (GtkWidget *view,
504 GtkAllocation *allocation,
509 gtk_widget_get_size_request (box, NULL, &height);
511 width = allocation->width;
514 gtk_text_view_get_right_margin (GTK_TEXT_VIEW (view)) - \
515 gtk_text_view_get_left_margin (GTK_TEXT_VIEW (view));
517 width -= 2 * HEADER_PADDING;
519 gtk_widget_set_size_request (box, width, height);
523 theme_boxes_maybe_append_header (EmpathyTheme *theme,
524 EmpathyChatView *view,
527 EmpathyThemeBoxesPriv *priv;
528 EmpathyContact *contact;
529 EmpathyContact *last_contact;
530 GdkPixbuf *avatar = NULL;
531 GtkTextBuffer *buffer;
534 GtkWidget *label1, *label2;
535 GtkTextChildAnchor *anchor;
542 gboolean parse_success;
544 priv = GET_PRIV (theme);
546 contact = empathy_message_get_sender (msg);
547 name = empathy_contact_get_name (contact);
548 last_contact = empathy_chat_view_get_last_contact (view);
549 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
551 DEBUG ("Maybe add fancy header");
553 /* Only insert a header if the previously inserted block is not the same
554 * as this one. This catches all the different cases:
556 if (last_contact && empathy_contact_equal (last_contact, contact)) {
560 empathy_theme_append_spacing (theme, view);
562 gtk_text_buffer_get_end_iter (buffer, &iter);
563 gtk_text_buffer_insert_with_tags_by_name (buffer,
570 gtk_text_buffer_get_end_iter (buffer, &iter);
571 anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
573 box = gtk_hbox_new (FALSE, 0);
576 if (empathy_theme_get_show_avatars (theme)) {
577 avatar = empathy_chat_view_get_avatar_pixbuf_with_cache (contact);
581 image = gtk_image_new_from_pixbuf (avatar);
583 gtk_box_pack_start (GTK_BOX (box), image,
588 g_signal_connect_object (view, "size-allocate",
589 G_CALLBACK (table_size_allocate_cb),
592 str = g_markup_printf_escaped ("<b>%s</b>", name);
594 label1 = g_object_new (GTK_TYPE_LABEL,
600 parse_success = priv->header_foreground &&
601 gdk_color_parse (priv->header_foreground, &color);
604 gtk_widget_modify_fg (label1, GTK_STATE_NORMAL, &color);
609 time = empathy_message_get_timestamp (msg);
611 tmp = empathy_time_to_string_local (time,
612 EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
613 str = g_strdup_printf ("<i>%s</i>", tmp);
616 label2 = g_object_new (GTK_TYPE_LABEL,
623 gtk_widget_modify_fg (label2, GTK_STATE_NORMAL, &color);
628 gtk_misc_set_alignment (GTK_MISC (label1), 0.0, 0.5);
629 gtk_misc_set_alignment (GTK_MISC (label2), 1.0, 0.5);
631 gtk_box_pack_start (GTK_BOX (box), label1, TRUE, TRUE, 0);
632 gtk_box_pack_start (GTK_BOX (box), label2, TRUE, TRUE, 0);
634 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view),
638 gtk_widget_show_all (box);
640 gtk_text_buffer_get_end_iter (buffer, &iter);
642 gtk_text_iter_backward_char (&start);
643 gtk_text_buffer_apply_tag_by_name (buffer,
647 gtk_text_buffer_insert_with_tags_by_name (buffer,
654 gtk_text_buffer_get_end_iter (buffer, &iter);
655 gtk_text_buffer_insert_with_tags_by_name (buffer,
664 theme_boxes_append_message (EmpathyTheme *theme,
665 EmpathyChatView *view,
666 EmpathyMessage *message)
668 EmpathyContact *sender;
670 empathy_theme_maybe_append_date_and_time (theme, view, message);
671 theme_boxes_maybe_append_header (theme, view, message);
673 sender = empathy_message_get_sender (message);
675 if (empathy_message_get_type (message) == EMPATHY_MESSAGE_TYPE_ACTION) {
678 body = g_strdup_printf (" * %s %s",
679 empathy_contact_get_name (sender),
680 empathy_message_get_body (message));
681 empathy_theme_append_text (theme, view, body,
682 "fancy-action", "fancy-link");
684 empathy_theme_append_text (theme, view,
685 empathy_message_get_body (message),
686 "fancy-body", "fancy-link");
691 theme_boxes_append_event (EmpathyTheme *theme,
692 EmpathyChatView *view,
695 GtkTextBuffer *buffer;
699 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
701 empathy_theme_maybe_append_date_and_time (theme, view, NULL);
703 gtk_text_buffer_get_end_iter (buffer, &iter);
705 msg = g_strdup_printf (" - %s\n", str);
707 gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
715 theme_boxes_append_timestamp (EmpathyTheme *theme,
716 EmpathyChatView *view,
717 EmpathyMessage *message,
721 GtkTextBuffer *buffer;
731 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
733 date = empathy_message_get_date_and_time (message, ×tamp);
735 str = g_string_new (NULL);
737 if (show_time || show_date) {
738 empathy_theme_append_spacing (theme, view);
740 g_string_append (str, "- ");
746 g_date_strftime (buf, 256, _("%A %d %B %Y"), date);
747 g_string_append (str, buf);
750 g_string_append (str, ", ");
759 tmp = empathy_time_to_string_local (timestamp, EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
760 g_string_append (str, tmp);
764 if (show_time || show_date) {
765 g_string_append (str, " -\n");
767 gtk_text_buffer_get_end_iter (buffer, &iter);
768 gtk_text_buffer_insert_with_tags_by_name (buffer,
774 empathy_chat_view_set_last_timestamp (view, timestamp);
777 g_string_free (str, TRUE);
782 theme_boxes_append_spacing (EmpathyTheme *theme,
783 EmpathyChatView *view)
785 GtkTextBuffer *buffer;
788 g_return_if_fail (EMPATHY_IS_THEME (theme));
789 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
791 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
793 gtk_text_buffer_get_end_iter (buffer, &iter);
794 gtk_text_buffer_insert_with_tags_by_name (buffer,