#include <telepathy-glib/util.h>
#include <libempathy/empathy-utils.h>
-#include <libempathy/empathy-account.h>
#include "empathy-chat-text-view.h"
#include "empathy-chat.h"
static void chat_text_view_iface_init (EmpathyChatViewIface *iface);
+static void chat_text_view_copy_clipboard (EmpathyChatView *view);
+
G_DEFINE_TYPE_WITH_CODE (EmpathyChatTextView, empathy_chat_text_view,
GTK_TYPE_TEXT_VIEW,
G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CHAT_VIEW,
EmpathyChatTextViewPriv *priv;
GtkTextIter top, bottom;
gint line;
- gint remove;
+ gint remove_;
GtkTextTagTable *table;
GtkTextTag *tag;
return;
}
- remove = line - MAX_LINES;
+ remove_ = line - MAX_LINES;
gtk_text_buffer_get_start_iter (priv->buffer, &top);
bottom = top;
- if (!gtk_text_iter_forward_lines (&bottom, remove)) {
+ if (!gtk_text_iter_forward_lines (&bottom, remove_)) {
return;
}
GdkDragContext *context,
gint x,
gint y,
- guint time)
+ guint time_)
{
/* Don't handle drag motion, since we don't want the view to scroll as
* the result of dragging something across it. */
G_OBJECT_CLASS (empathy_chat_text_view_parent_class)->finalize (object);
}
+static void
+text_view_copy_clipboard (GtkTextView *text_view)
+{
+ chat_text_view_copy_clipboard (EMPATHY_CHAT_VIEW (text_view));
+}
+
static void
empathy_chat_text_view_class_init (EmpathyChatTextViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkTextViewClass *text_view_class = GTK_TEXT_VIEW_CLASS (klass);
object_class->finalize = chat_text_view_finalize;
object_class->get_property = chat_text_view_get_property;
widget_class->size_allocate = chat_text_view_size_allocate;
widget_class->drag_motion = chat_text_view_drag_motion;
+ text_view_class->copy_clipboard = text_view_copy_clipboard;
+
g_object_class_install_property (object_class,
PROP_LAST_CONTACT,
g_param_spec_object ("last-contact",
chat_text_view_copy_clipboard (EmpathyChatView *view)
{
GtkTextBuffer *buffer;
+ GtkTextIter start, iter, end;
GtkClipboard *clipboard;
+ GdkPixbuf *pixbuf;
+ gunichar c;
+ GtkTextChildAnchor *anchor = NULL;
+ GString *str;
+ GList *list;
+ gboolean ignore_newlines = FALSE;
g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- gtk_text_buffer_copy_clipboard (buffer, clipboard);
+ if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+ return;
+
+ str = g_string_new ("");
+
+ for (iter = start; !gtk_text_iter_equal (&iter, &end); gtk_text_iter_forward_char (&iter)) {
+ c = gtk_text_iter_get_char (&iter);
+ /* 0xFFFC is the 'object replacement' unicode character,
+ * it indicates the presence of a pixbuf or a widget. */
+ if (c == 0xFFFC) {
+ ignore_newlines = FALSE;
+ if ((pixbuf = gtk_text_iter_get_pixbuf (&iter))) {
+ gchar *text;
+ text = g_object_get_data (G_OBJECT(pixbuf),
+ "smiley_str");
+ if (text)
+ str = g_string_append (str, text);
+ } else if ((anchor = gtk_text_iter_get_child_anchor (&iter))) {
+ gchar *text;
+ list = gtk_text_child_anchor_get_widgets (anchor);
+ if (list) {
+ text = g_object_get_data (G_OBJECT(list->data),
+ "str_obj");
+ if (text)
+ str = g_string_append (str, text);
+ }
+ g_list_free (list);
+ }
+ } else if (c == '\n') {
+ if (!ignore_newlines) {
+ ignore_newlines = TRUE;
+ str = g_string_append_unichar (str, c);
+ }
+ } else {
+ ignore_newlines = FALSE;
+ str = g_string_append_unichar (str, c);
+ }
+ }
+
+ gtk_clipboard_set_text (clipboard, str->str, str->len);
+ g_string_free (str, TRUE);
}
static void
}
static void
-chat_text_view_insert_text_with_emoticons (EmpathyChatTextView *view,
- GtkTextIter *iter,
- const gchar *str)
+chat_text_view_replace_link (const gchar *text,
+ gssize len,
+ gpointer match_data,
+ gpointer user_data)
{
- EmpathyChatTextViewPriv *priv = GET_PRIV (view);
- gboolean use_smileys = FALSE;
- GSList *smileys, *l;
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (user_data);
+ GtkTextIter iter;
- empathy_conf_get_bool (empathy_conf_get (),
- EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
- &use_smileys);
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+ text, len,
+ EMPATHY_CHAT_TEXT_VIEW_TAG_LINK,
+ NULL);
+}
- if (!use_smileys) {
- gtk_text_buffer_insert (priv->buffer, iter, str, -1);
- return;
- }
+static void
+chat_text_view_replace_smiley (const gchar *text,
+ gssize len,
+ gpointer match_data,
+ gpointer user_data)
+{
+ EmpathySmileyHit *hit = match_data;
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (user_data);
+ GtkTextIter iter;
- smileys = empathy_smiley_manager_parse (priv->smiley_manager, str);
- for (l = smileys; l; l = l->next) {
- EmpathySmiley *smiley;
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert_pixbuf (buffer, &iter, hit->pixbuf);
+}
- smiley = l->data;
- if (smiley->pixbuf) {
- gtk_text_buffer_insert_pixbuf (priv->buffer, iter, smiley->pixbuf);
- } else {
- gtk_text_buffer_insert (priv->buffer, iter, smiley->str, -1);
- }
- empathy_smiley_free (smiley);
- }
- g_slist_free (smileys);
+static void
+chat_text_view_replace_verbatim (const gchar *text,
+ gssize len,
+ gpointer match_data,
+ gpointer user_data)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (user_data);
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter (buffer, &iter);
+ gtk_text_buffer_insert (buffer, &iter, text, len);
}
+static EmpathyStringParser string_parsers[] = {
+ {empathy_string_match_link, chat_text_view_replace_link},
+ {empathy_string_match_all, chat_text_view_replace_verbatim},
+ {NULL, NULL}
+};
+
+static EmpathyStringParser string_parsers_with_smiley[] = {
+ {empathy_string_match_link, chat_text_view_replace_link},
+ {empathy_string_match_smiley, chat_text_view_replace_smiley},
+ {empathy_string_match_all, chat_text_view_replace_verbatim},
+ {NULL, NULL}
+};
+
void
empathy_chat_text_view_append_body (EmpathyChatTextView *view,
const gchar *body,
const gchar *tag)
{
EmpathyChatTextViewPriv *priv = GET_PRIV (view);
- GtkTextIter start_iter, end_iter;
- GtkTextMark *mark;
+ EmpathyStringParser *parsers;
+ gboolean use_smileys;
+ GtkTextIter start_iter;
GtkTextIter iter;
- GRegex *uri_regex;
- GMatchInfo *match_info;
- gboolean match;
- gint last = 0;
- gint s = 0, e = 0;
- gchar *tmp;
+ GtkTextMark *mark;
- priv = GET_PRIV (view);
+ /* Check if we have to parse smileys */
+ empathy_conf_get_bool (empathy_conf_get (),
+ EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
+ &use_smileys);
+ if (use_smileys)
+ parsers = string_parsers_with_smiley;
+ else
+ parsers = string_parsers;
+ /* Create a mark at the place we'll start inserting */
gtk_text_buffer_get_end_iter (priv->buffer, &start_iter);
mark = gtk_text_buffer_create_mark (priv->buffer, NULL, &start_iter, TRUE);
- uri_regex = empathy_uri_regex_dup_singleton ();
- for (match = g_regex_match (uri_regex, body, 0, &match_info); match;
- match = g_match_info_next (match_info, NULL)) {
- if (!g_match_info_fetch_pos (match_info, 0, &s, &e))
- continue;
-
- if (s > last) {
- tmp = empathy_substring (body, last, s);
-
- gtk_text_buffer_get_end_iter (priv->buffer, &iter);
- chat_text_view_insert_text_with_emoticons (view,
- &iter,
- tmp);
- g_free (tmp);
- }
-
- tmp = empathy_substring (body, s, e);
-
- gtk_text_buffer_get_end_iter (priv->buffer, &iter);
- gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
- &iter,
- tmp,
- -1,
- EMPATHY_CHAT_TEXT_VIEW_TAG_LINK,
- NULL);
-
- g_free (tmp);
- last = e;
- }
- g_match_info_free (match_info);
- g_regex_unref (uri_regex);
-
- if (last < strlen (body)) {
- gtk_text_buffer_get_end_iter (priv->buffer, &iter);
- chat_text_view_insert_text_with_emoticons (view,
- &iter,
- body + last);
- }
+ /* Parse text for links/smileys and insert in the buffer */
+ empathy_string_parser_substr (body, -1, parsers, priv->buffer);
+ /* Insert a newline after the text inserted */
gtk_text_buffer_get_end_iter (priv->buffer, &iter);
gtk_text_buffer_insert (priv->buffer, &iter, "\n", 1);
/* Apply the style to the inserted text. */
gtk_text_buffer_get_iter_at_mark (priv->buffer, &start_iter, mark);
- gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
-
- gtk_text_buffer_apply_tag_by_name (priv->buffer,
- tag,
+ gtk_text_buffer_get_end_iter (priv->buffer, &iter);
+ gtk_text_buffer_apply_tag_by_name (priv->buffer, tag,
&start_iter,
- &end_iter);
+ &iter);
gtk_text_buffer_delete_mark (priv->buffer, mark);
}