diff options
Diffstat (limited to 'widgets/text/e-text-model-uri.c')
-rw-r--r-- | widgets/text/e-text-model-uri.c | 231 |
1 files changed, 186 insertions, 45 deletions
diff --git a/widgets/text/e-text-model-uri.c b/widgets/text/e-text-model-uri.c index bd8dbb18e8..b769d0b70a 100644 --- a/widgets/text/e-text-model-uri.c +++ b/widgets/text/e-text-model-uri.c @@ -9,15 +9,21 @@ #include <config.h> #include <ctype.h> +#include <sys/types.h> +#include <regex.h> #include "e-text-model-uri.h" static void e_text_model_uri_class_init (ETextModelURIClass *class); static void e_text_model_uri_init (ETextModelURI *model); static void e_text_model_uri_destroy (GtkObject *object); -static void objectify_uris (ETextModelURI *model); +static void objectify_uris (ETextModelURI *model, gint position); static void e_text_model_uri_set_text (ETextModel *model, gchar *text); +static void e_text_model_uri_insert (ETextModel *model, gint position, gchar *text); +static void e_text_model_uri_insert_length (ETextModel *model, gint position, gchar *text, gint length); +static void e_text_model_uri_delete (ETextModel *model, gint position, gint length); + static const gchar *e_text_model_uri_get_nth_object (ETextModel *model, gint); static void e_text_model_uri_activate_nth_object (ETextModel *model, gint); @@ -60,6 +66,10 @@ e_text_model_uri_class_init (ETextModelURIClass *klass) object_class->destroy = e_text_model_uri_destroy; model_class->set_text = e_text_model_uri_set_text; + model_class->insert = e_text_model_uri_insert; + model_class->insert_length = e_text_model_uri_insert_length; + model_class->delete = e_text_model_uri_delete; + model_class->get_nth_obj = e_text_model_uri_get_nth_object; model_class->activate_nth_obj = e_text_model_uri_activate_nth_object; } @@ -78,66 +88,169 @@ e_text_model_uri_destroy (GtkObject *object) } -static gchar * -extract_uri (gchar **in_str) +/* URL regexps taken from gnome-terminal */ +static const gchar *url_regexs[3] = { + "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp))[-A-Za-z0-9\\.]+(:[0-9]*)?/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]", + "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp))[-A-Za-z0-9\\.]+[-A-Za-z0-9](:[0-9]*)?", + "mailto:[A-Za-z0-9_]+@[-A-Za-z0-9_]+\\.[-A-Za-z0-9\\.]+[-A-Za-z0-9]" +}; + +static void +objectify_uris (ETextModelURI *model_uri, gint position) { - gchar *s = *in_str; - if (strncmp (s, "http://", 7) == 0) { - gint periods=0; - gchar *uri; + static gboolean initialized = FALSE; + static regex_t re_full, re_part, re_mail; - s += 7; + ETextModel *model = E_TEXT_MODEL (model_uri); + regmatch_t match; + GList *uris = NULL, *iter; + gint i, j, offset, last, len, objN; + gchar *in_str, *new_str; + gint new_position = position, pos_adjust=0; - while (*s && (isalnum((gint) *s) || (*s == '.' && periods < 2))) { - if (*s == '.') - ++periods; - ++s; - } + if (model->text == NULL) + return; + + if (!initialized) { - uri = g_strndup (*in_str, s - *in_str); - *in_str = s; - return uri; + if (regcomp (&re_full, url_regexs[0], REG_EXTENDED)) + g_error ("Regex compile failed: %s", url_regexs[0]); + if (regcomp (&re_part, url_regexs[1], REG_EXTENDED)) + g_error ("Regex compile failed: %s", url_regexs[1]); + if (regcomp (&re_mail, url_regexs[2], REG_EXTENDED)) + g_error ("Regex compile failed: %s", url_regexs[2]); - } else { - *in_str = s+1; - return NULL; + + initialized = TRUE; } -} -static void -objectify_uris (ETextModelURI *model_uri) -{ - ETextModel *model = E_TEXT_MODEL (model_uri); - gchar *new_text; - gchar *src, *dest; - GList *uris = NULL; + /*** Expand objects in string, keeping track of position shifts ***/ + + objN = e_text_model_object_count (model); + if (objN == 0) + in_str = g_strdup (model->text); + else { + gchar *src, *dest; + + /* Calculate length of expanded string. */ + len = strlen (model->text) - objN; + for (i=0; i<objN; ++i) + len += strlen (e_text_model_get_nth_object (model, i)); + + in_str = g_new0 (gchar, len+1); + + src = model->text; + dest = in_str; + i = 0; /* object numbers */ + j = 0; /* string position */ + while (*src) { + if (*src == '\1') { + const gchar *src_obj; + + src_obj = e_text_model_get_nth_object (model, i); + + if (j < position) + new_position += strlen (src_obj)-1; + + if (src_obj) { + while (*src_obj) { + *dest = *src_obj; + ++dest; + ++src_obj; + } + } + + ++src; + ++i; + ++j; + + } else { + + *dest = *src; + ++src; + ++dest; + ++j; + } + } + } - if (model->text == NULL) - return; + len = strlen (in_str); + new_str = g_new0 (gchar, len+1); + + offset = 0; + j = 0; + last = 0; + while (offset < len + && (regexec (&re_full, in_str+offset, 1, &match, 0) == 0 + || regexec (&re_part, in_str+offset, 1, &match, 0) == 0 + || regexec (&re_mail, in_str+offset, 1, &match, 0) == 0)) { - new_text = g_new0 (gchar, strlen (model->text)+1); + gchar *uri_txt; - src = model->text; - dest = new_text; + if (offset+match.rm_so <= new_position + && new_position <= offset+match.rm_eo) { + + /* We don't do transformations that straddle our cursor. */ + new_str[j] = in_str[offset]; + ++j; + ++offset; - while (*src) { - gchar *uri_str; - gchar *next = src; - if ( (uri_str = extract_uri (&next)) ) { - uris = g_list_append (uris, uri_str); - *dest = '\1'; } else { - *dest = *src; + + for (i=offset; i<offset+match.rm_so; ++i) { + new_str[j] = in_str[i]; + ++j; + } + + new_str[j] = '\1'; + ++j; + + uri_txt = g_strndup (in_str+offset+match.rm_so, + match.rm_eo - match.rm_so); + uris = g_list_append (uris, uri_txt); + + if (offset+match.rm_so < new_position) + pos_adjust += match.rm_eo - match.rm_so - 1; + + offset += match.rm_eo; } - ++dest; - src = next; + } + new_position -= pos_adjust; + + /* Copy the last bit over. */ + while (offset < len) { + new_str[j] = in_str[offset]; + ++j; + ++offset; } - g_free (model->text); - model->text = new_text; +#if 0 + for (i=0; i<strlen(new_str); ++i) { + if (i == new_position) + putchar ('#'); + if (new_str[i] == '\1') + g_print ("[\1]"); + else + putchar (new_str[i]); + } + putchar ('\n'); +#endif - /* Leaking old list */ + for (iter = model_uri->uris; iter != NULL; iter = g_list_next (iter)) + g_free (iter->data); + g_list_free (model_uri->uris); model_uri->uris = uris; + + g_free (in_str); + + if (E_TEXT_MODEL_CLASS(parent_class)->set_text) + E_TEXT_MODEL_CLASS(parent_class)->set_text (model, new_str); + + g_free (new_str); + + + if (new_position != position) + e_text_model_suggest_position (model, new_position); } static void @@ -146,7 +259,35 @@ e_text_model_uri_set_text (ETextModel *model, gchar *text) if (E_TEXT_MODEL_CLASS(parent_class)->set_text) E_TEXT_MODEL_CLASS(parent_class)->set_text (model, text); - objectify_uris (E_TEXT_MODEL_URI (model)); + objectify_uris (E_TEXT_MODEL_URI (model), 0); +} + +static void +e_text_model_uri_insert (ETextModel *model, gint position, gchar *text) +{ + if (E_TEXT_MODEL_CLASS(parent_class)->insert) + E_TEXT_MODEL_CLASS(parent_class)->insert (model, position, text); + + objectify_uris (E_TEXT_MODEL_URI (model), position + strlen (text)); +} + +static void +e_text_model_uri_insert_length (ETextModel *model, gint position, gchar *text, gint length) +{ + + if (E_TEXT_MODEL_CLASS(parent_class)->insert_length) + E_TEXT_MODEL_CLASS(parent_class)->insert_length (model, position, text, length); + + objectify_uris (E_TEXT_MODEL_URI (model), position + length); +} + +static void +e_text_model_uri_delete (ETextModel *model, gint position, gint length) +{ + if (E_TEXT_MODEL_CLASS(parent_class)->delete) + E_TEXT_MODEL_CLASS(parent_class)->delete (model, position, length); + + objectify_uris (E_TEXT_MODEL_URI (model), position); } static const gchar * |