aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/text/e-text-model-uri.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/text/e-text-model-uri.c')
-rw-r--r--widgets/text/e-text-model-uri.c231
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 *