diff options
Diffstat (limited to 'libempathy-gtk/empathy-theme-adium.c')
-rw-r--r-- | libempathy-gtk/empathy-theme-adium.c | 191 |
1 files changed, 173 insertions, 18 deletions
diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c index 0370b9055..bb2b189ca 100644 --- a/libempathy-gtk/empathy-theme-adium.c +++ b/libempathy-gtk/empathy-theme-adium.c @@ -59,7 +59,7 @@ typedef struct { gint64 last_timestamp; gboolean last_is_backlog; guint pages_loading; - /* Queue of GValue* containing an EmpathyMessage or string */ + /* Queue of QueuedItem*s containing an EmpathyMessage or string */ GQueue message_queue; /* Queue of owned gchar* of message token to remove unread * marker for when we lose focus. */ @@ -119,6 +119,45 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyThemeAdium, empathy_theme_adium, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CHAT_VIEW, theme_adium_iface_init)); +enum { + QUEUED_EVENT, + QUEUED_MESSAGE, + QUEUED_EDIT +}; + +typedef struct { + guint type; + EmpathyMessage *msg; + char *str; +} QueuedItem; + +static QueuedItem * +queue_item (GQueue *queue, + guint type, + EmpathyMessage *msg, + const char *str) +{ + QueuedItem *item = g_slice_new0 (QueuedItem); + + item->type = type; + if (msg != NULL) + item->msg = g_object_ref (msg); + item->str = g_strdup (str); + + g_queue_push_tail (queue, item); + + return item; +} + +static void +free_queued_item (QueuedItem *item) +{ + tp_clear_object (&item->msg); + g_free (item->str); + + g_slice_free (QueuedItem, item); +} + static void theme_adium_update_enable_webkit_developer_tools (EmpathyThemeAdium *theme) { @@ -315,7 +354,8 @@ static EmpathyStringParser string_parsers_with_smiley[] = { static gchar * theme_adium_parse_body (EmpathyThemeAdium *self, - const gchar *text) + const gchar *text, + const gchar *token) { EmpathyThemeAdiumPriv *priv = GET_PRIV (self); EmpathyStringParser *parsers; @@ -332,8 +372,19 @@ theme_adium_parse_body (EmpathyThemeAdium *self, * by html tags. Also escape text to make sure html code is * displayed verbatim. */ string = g_string_sized_new (strlen (text)); + + /* wrap this in HTML that allows us to find the message for later + * editing */ + if (!tp_str_empty (token)) + g_string_append_printf (string, + "<span id=\"message-token-%s\">", + token); + empathy_string_parser_substr (text, -1, parsers, string); + if (!tp_str_empty (token)) + g_string_append (string, "</span>"); + /* Wrap body in order to make tabs and multiple spaces displayed * properly. See bug #625745. */ g_string_prepend (string, "<div style=\"display: inline; " @@ -817,7 +868,6 @@ theme_adium_append_message (EmpathyChatView *view, TpMessage *tp_msg; TpAccount *account; gchar *body_escaped; - const gchar *body; const gchar *name; const gchar *contact_id; EmpathyAvatar *avatar; @@ -832,9 +882,7 @@ theme_adium_append_message (EmpathyChatView *view, gboolean action; if (priv->pages_loading != 0) { - GValue *value = tp_g_value_slice_new (EMPATHY_TYPE_MESSAGE); - g_value_set_object (value, msg); - g_queue_push_tail (&priv->message_queue, value); + queue_item (&priv->message_queue, QUEUED_MESSAGE, msg, NULL); return; } @@ -846,8 +894,9 @@ theme_adium_append_message (EmpathyChatView *view, if (service_name == NULL) service_name = tp_account_get_protocol (account); timestamp = empathy_message_get_timestamp (msg); - body = empathy_message_get_body (msg); - body_escaped = theme_adium_parse_body (theme, body); + body_escaped = theme_adium_parse_body (theme, + empathy_message_get_body (msg), + empathy_message_get_token (msg)); name = empathy_contact_get_alias (sender); contact_id = empathy_contact_get_id (sender); action = (empathy_message_get_tptype (msg) == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION); @@ -1005,8 +1054,7 @@ theme_adium_append_event (EmpathyChatView *view, gchar *str_escaped; if (priv->pages_loading != 0) { - g_queue_push_tail (&priv->message_queue, - tp_g_value_slice_new_string (str)); + queue_item (&priv->message_queue, QUEUED_EVENT, NULL, str); return; } @@ -1016,6 +1064,104 @@ theme_adium_append_event (EmpathyChatView *view, } static void +theme_adium_edit_message (EmpathyChatView *view, + EmpathyMessage *message) +{ + EmpathyThemeAdiumPriv *priv = GET_PRIV (view); + WebKitDOMDocument *doc; + WebKitDOMElement *span; + gchar *id, *parsed_body; + gchar *tooltip, *timestamp; + GtkIconInfo *icon_info; + GError *error = NULL; + + if (priv->pages_loading != 0) { + queue_item (&priv->message_queue, QUEUED_EDIT, message, NULL); + return; + } + + id = g_strdup_printf ("message-token-%s", + empathy_message_get_supersedes (message)); + /* we don't pass a token here, because doing so will return another + * <span> element, and we don't want nested <span> elements */ + parsed_body = theme_adium_parse_body (EMPATHY_THEME_ADIUM (view), + empathy_message_get_body (message), NULL); + + /* find the element */ + doc = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view)); + span = webkit_dom_document_get_element_by_id (doc, id); + + if (span == NULL) { + DEBUG ("Failed to find id '%s'", id); + goto except; + } + + if (!WEBKIT_DOM_IS_HTML_ELEMENT (span)) { + DEBUG ("Not a HTML element"); + goto except; + } + + /* update the HTML */ + webkit_dom_html_element_set_inner_html (WEBKIT_DOM_HTML_ELEMENT (span), + parsed_body, &error); + + if (error != NULL) { + DEBUG ("Error setting new inner-HTML: %s", error->message); + g_error_free (error); + goto except; + } + + /* set a tooltip */ + timestamp = empathy_time_to_string_local ( + empathy_message_get_timestamp (message), + "%H:%M:%S"); + tooltip = g_strdup_printf (_("Message edited at %s"), timestamp); + + webkit_dom_html_element_set_title (WEBKIT_DOM_HTML_ELEMENT (span), + tooltip); + + g_free (tooltip); + g_free (timestamp); + + /* mark this message as edited */ + icon_info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), + EMPATHY_IMAGE_EDIT_MESSAGE, 16, 0); + + if (icon_info != NULL) { + /* set the icon as a background image using CSS + * FIXME: the icon won't update in response to theme changes */ + gchar *style = g_strdup_printf ( + "background-image:url('%s');" + "background-repeat:no-repeat;" + "background-position:left center;" + "padding-left:19px;", /* 16px icon + 3px padding */ + gtk_icon_info_get_filename (icon_info)); + + webkit_dom_element_set_attribute (span, "style", style, &error); + + if (error != NULL) { + DEBUG ("Error setting element style: %s", + error->message); + g_clear_error (&error); + /* not fatal */ + } + + g_free (style); + gtk_icon_info_free (icon_info); + } + + goto finally; + +except: + DEBUG ("Could not find message to edit with: %s", + empathy_message_get_body (message)); + +finally: + g_free (id); + g_free (parsed_body); +} + +static void theme_adium_scroll (EmpathyChatView *view, gboolean allow_scrolling) { @@ -1311,6 +1457,7 @@ theme_adium_iface_init (EmpathyChatViewIface *iface) { iface->append_message = theme_adium_append_message; iface->append_event = theme_adium_append_event; + iface->edit_message = theme_adium_edit_message; iface->scroll = theme_adium_scroll; iface->scroll_down = theme_adium_scroll_down; iface->get_has_selection = theme_adium_get_has_selection; @@ -1341,18 +1488,26 @@ theme_adium_load_finished_cb (WebKitWebView *view, /* Display queued messages */ for (l = priv->message_queue.head; l != NULL; l = l->next) { - GValue *value = l->data; + QueuedItem *item = l->data; - if (G_VALUE_HOLDS_OBJECT (value)) { - theme_adium_append_message (chat_view, - g_value_get_object (value)); - } else { - theme_adium_append_event (chat_view, - g_value_get_string (value)); + switch (item->type) + { + case QUEUED_MESSAGE: + theme_adium_append_message (chat_view, item->msg); + break; + + case QUEUED_EDIT: + theme_adium_edit_message (chat_view, item->msg); + break; + + case QUEUED_EVENT: + theme_adium_append_event (chat_view, item->str); + break; } - tp_g_value_slice_free (value); + free_queued_item (item); } + g_queue_clear (&priv->message_queue); } |