From bd603ce6e5945ed1d06e550c928fc2ed21da3d88 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 16 Jul 2008 16:45:29 +0200 Subject: Add initial adium theme support: Load the template and append messages. --- libempathy-gtk/empathy-theme-adium.c | 288 +++++++++++++++++++++++++++++++++-- libempathy/empathy-contact.c | 12 ++ libempathy/empathy-contact.h | 1 + 3 files changed, 285 insertions(+), 16 deletions(-) diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c index 221cf21db..9c5efc9cd 100644 --- a/libempathy-gtk/empathy-theme-adium.c +++ b/libempathy-gtk/empathy-theme-adium.c @@ -20,6 +20,10 @@ */ #include "config.h" +#include + +#include +#include #include "empathy-theme-adium.h" @@ -29,7 +33,17 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyThemeAdium) typedef struct { - guint unused; + gchar *in_content_html; + gsize in_content_len; + gchar *in_nextcontent_html; + gsize in_nextcontent_len; + gchar *out_content_html; + gsize out_content_len; + gchar *out_nextcontent_html; + gsize out_nextcontent_len; + EmpathyContact *last_contact; + gboolean ready; + GList *message_queue; } EmpathyThemeAdiumPriv; static void theme_adium_iface_init (EmpathyChatViewIface *iface); @@ -40,62 +54,235 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyThemeAdium, empathy_theme_adium, theme_adium_iface_init)); static void -theme_adium_finalize (GObject *object) +theme_adium_load (EmpathyThemeAdium *theme) { - G_OBJECT_CLASS (empathy_theme_adium_parent_class)->finalize (object); -} + EmpathyThemeAdiumPriv *priv = GET_PRIV (theme); + gchar *basedir; + gchar *file; + gchar *template_html; + gsize template_len; + GString *string; + gchar **strv; + gchar *content; + gchar *css_path; -static void -empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = theme_adium_finalize; + /* FIXME: Find a better way to get the theme dir */ + basedir = g_build_filename (g_get_home_dir (), "Contents", "Resources", NULL); - g_type_class_add_private (object_class, sizeof (EmpathyThemeAdiumPriv)); + /* Load html files */ + file = g_build_filename (basedir, "Template.html", NULL); + g_file_get_contents (file, &template_html, &template_len, NULL); + g_free (file); + + file = g_build_filename (basedir, "Incoming", "Content.html", NULL); + g_file_get_contents (file, &priv->in_content_html, &priv->in_content_len, NULL); + g_free (file); + + file = g_build_filename (basedir, "Incoming", "NextContent.html", NULL); + g_file_get_contents (file, &priv->in_nextcontent_html, &priv->in_nextcontent_len, NULL); + g_free (file); + + file = g_build_filename (basedir, "Outgoing", "Content.html", NULL); + g_file_get_contents (file, &priv->out_content_html, &priv->out_content_len, NULL); + g_free (file); + + file = g_build_filename (basedir, "Outgoing", "NextContent.html", NULL); + g_file_get_contents (file, &priv->out_nextcontent_html, &priv->out_nextcontent_len, NULL); + g_free (file); + + css_path = g_build_filename (basedir, "main.css", NULL); + + /* Replace %@ with the needed information in the template html */ + strv = g_strsplit (template_html, "%@", 5); + string = g_string_sized_new (template_len); + g_string_append (string, strv[0]); + g_string_append (string, basedir); + g_string_append (string, strv[1]); + g_string_append (string, css_path); + g_string_append (string, strv[2]); + g_string_append (string, ""); /* We don't want header */ + g_string_append (string, strv[3]); + g_string_append (string, ""); /* We have no footer */ + g_string_append (string, strv[4]); + content = g_string_free (string, FALSE); + + /* Load the template */ + webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (theme), + content, basedir); + + g_free (basedir); + g_free (content); + g_free (template_html); + g_free (css_path); + g_strfreev (strv); } -static void -empathy_theme_adium_init (EmpathyThemeAdium *theme) +static gchar * +theme_adium_escape (EmpathyThemeAdium *theme, + const gchar *text) { - EmpathyThemeAdiumPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (theme, - EMPATHY_TYPE_THEME_ADIUM, EmpathyThemeAdiumPriv); + const gchar *cur = text; + GString *string; - theme->priv = priv; + string = g_string_sized_new (strlen (text)); + while (!G_STR_EMPTY (cur)) { + switch (*cur) { + case '\\': + g_string_append (string, "\\\\"); + break; + case '\"': + g_string_append (string, "\\\""); + break; + case '\r': + g_string_append (string, "
"); + break; + case '\n': + break; + default: + g_string_append_c (string, *cur); + } + cur++; + } + + return g_string_free (string, FALSE); } static void theme_adium_scroll_down (EmpathyChatView *view) { + /* Not implemented */ } static void theme_adium_append_message (EmpathyChatView *view, EmpathyMessage *msg) { + EmpathyThemeAdiumPriv *priv = GET_PRIV (view); + EmpathyContact *sender; + const gchar *body; + const gchar *name; + gchar *avatar; + gchar *time; + gsize len; + GString *string; + gchar *cur; + gchar *prev; + gchar *script; + gchar *escape; + const gchar *func; + + if (!priv->ready) { + priv->message_queue = g_list_prepend (priv->message_queue, + g_object_ref (msg)); + return; + } + + /* Get information */ + sender = empathy_message_get_sender (msg); + body = empathy_message_get_body (msg); + name = empathy_contact_get_name (sender); + avatar = empathy_contact_get_avatar_filename (sender); + time = empathy_time_to_string_local (empathy_message_get_timestamp (msg), + EMPATHY_TIME_FORMAT_DISPLAY_SHORT); + + if (!avatar) { + /* FIXME: We should give a default icon of a buddy */ + avatar = g_strdup ("FIXME"); + } + + /* Get the right html/func to add the message */ + if (priv->last_contact && + empathy_contact_equal (priv->last_contact, sender)) { + func = "appendNextMessage"; + if (empathy_contact_is_user (sender)) { + cur = priv->out_nextcontent_html; + len = priv->out_nextcontent_len; + } else { + cur = priv->in_nextcontent_html; + len = priv->in_nextcontent_len; + } + } else { + func = "appendMessage"; + if (empathy_contact_is_user (sender)) { + cur = priv->out_content_html; + len = priv->out_content_len; + } else { + cur = priv->in_content_html; + len = priv->in_content_len; + } + } + + /* Make some search-and-replece in the html code */ + prev = cur; + string = g_string_sized_new (len + strlen (body)); + while ((cur = strchr (cur, '%'))) { + const gchar *replace = NULL; + + if (!strncmp (cur, "%message%", strlen ("%message%"))) { + replace = body; + } else if (!strncmp (cur, "%time", strlen("%time"))) { + replace = time; + } else if (!strncmp (cur, "%userIconPath%", strlen("%userIconPath%"))) { + replace = avatar; + } else if (!strncmp(cur, "%sender%", strlen("%sender%"))) { + replace = name; + } else { + cur++; + continue; + } + + /* Here we have a replacement to make */ + g_string_append_len (string, prev, cur - prev); + g_string_append (string, replace); + + /* And update the pointers */ + prev = cur = strchr (cur + 1, '%') + 1; + } + g_string_append (string, prev); + + /* Execute a js to add the message */ + cur = g_string_free (string, FALSE); + escape = theme_adium_escape (EMPATHY_THEME_ADIUM (view), cur); + script = g_strdup_printf("%s(\"%s\")", func, escape); + webkit_web_view_execute_script (WEBKIT_WEB_VIEW (view), script); + + /* Keep the sender of the last displayed message */ + if (priv->last_contact) { + g_object_unref (priv->last_contact); + } + priv->last_contact = g_object_ref (sender); + + g_free (time); + g_free (avatar); + g_free (cur); + g_free (script); } static void theme_adium_append_event (EmpathyChatView *view, const gchar *str) { + /* Not implemented */ } static void theme_adium_scroll (EmpathyChatView *view, gboolean allow_scrolling) { + /* Not implemented */ } static gboolean theme_adium_get_has_selection (EmpathyChatView *view) { + /* Not implemented */ return FALSE; } static void theme_adium_clear (EmpathyChatView *view) { + /* Not implemented */ } static gboolean @@ -103,6 +290,7 @@ theme_adium_find_previous (EmpathyChatView *view, const gchar *search_criteria, gboolean new_search) { + /* Not implemented */ return FALSE; } @@ -111,6 +299,7 @@ theme_adium_find_next (EmpathyChatView *view, const gchar *search_criteria, gboolean new_search) { + /* Not implemented */ return FALSE; } @@ -120,17 +309,20 @@ theme_adium_find_abilities (EmpathyChatView *view, gboolean *can_do_previous, gboolean *can_do_next) { + /* Not implemented */ } static void theme_adium_highlight (EmpathyChatView *view, const gchar *text) { + /* Not implemented */ } static void theme_adium_copy_clipboard (EmpathyChatView *view) { + /* Not implemented */ } static void @@ -149,6 +341,70 @@ theme_adium_iface_init (EmpathyChatViewIface *iface) iface->copy_clipboard = theme_adium_copy_clipboard; } +static void +theme_adium_load_finished_cb (WebKitWebView *view, + WebKitWebFrame *frame, + gpointer user_data) +{ + EmpathyThemeAdiumPriv *priv = GET_PRIV (view); + EmpathyChatView *chat_view = EMPATHY_CHAT_VIEW (view); + + DEBUG ("Page loaded"); + priv->ready = TRUE; + + /* Display queued messages */ + priv->message_queue = g_list_reverse (priv->message_queue); + while (priv->message_queue) { + EmpathyMessage *message = priv->message_queue->data; + + theme_adium_append_message (chat_view, message); + priv->message_queue = g_list_remove (priv->message_queue, message); + g_object_unref (message); + } +} + +static void +theme_adium_finalize (GObject *object) +{ + EmpathyThemeAdiumPriv *priv = GET_PRIV (object); + + g_free (priv->in_content_html); + g_free (priv->in_nextcontent_html); + g_free (priv->out_content_html); + g_free (priv->out_nextcontent_html); + + if (priv->last_contact) { + g_object_unref (priv->last_contact); + } + + G_OBJECT_CLASS (empathy_theme_adium_parent_class)->finalize (object); +} + +static void +empathy_theme_adium_class_init (EmpathyThemeAdiumClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = theme_adium_finalize; + + g_type_class_add_private (object_class, sizeof (EmpathyThemeAdiumPriv)); +} + +static void +empathy_theme_adium_init (EmpathyThemeAdium *theme) +{ + EmpathyThemeAdiumPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (theme, + EMPATHY_TYPE_THEME_ADIUM, EmpathyThemeAdiumPriv); + + theme->priv = priv; + + theme_adium_load (theme); + + g_signal_connect (theme, "load-finished", + G_CALLBACK (theme_adium_load_finished_cb), + NULL); +} + EmpathyThemeAdium * empathy_theme_adium_new (void) { diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c index 01087c19d..6800c8e30 100644 --- a/libempathy/empathy-contact.c +++ b/libempathy/empathy-contact.c @@ -938,6 +938,18 @@ empathy_contact_load_avatar_cache (EmpathyContact *contact, return data != NULL; } +gchar * +empathy_contact_get_avatar_filename (EmpathyContact *contact) +{ + EmpathyContactPriv *priv = GET_PRIV (contact); + + if (priv->avatar) + return contact_get_avatar_filename (contact, priv->avatar->token); + + return NULL; +} + + GType empathy_avatar_get_type (void) { diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h index ff8d426e2..0d02dabc2 100644 --- a/libempathy/empathy-contact.h +++ b/libempathy/empathy-contact.h @@ -107,6 +107,7 @@ void empathy_contact_load_avatar_data (EmpathyContact *contact, const gchar *token); gboolean empathy_contact_load_avatar_cache (EmpathyContact *contact, const gchar *token); +gchar * empathy_contact_get_avatar_filename (EmpathyContact *contact); #define EMPATHY_TYPE_AVATAR (empathy_avatar_get_type ()) -- cgit v1.2.3