2012-10-25 [colin] 3.8.1cvs107
[claws.git] / src / textview.c
index baa21fea8b4dbb3d0860ffe1728917074f37c538..b47a8813812efec3eec64e3234d9100f0a20ac6a 100644 (file)
@@ -74,6 +74,8 @@
 #include "inputdialog.h"
 #include "timing.h"
 #include "tags.h"
+#include "manage_window.h"
+#include "folder_item_prefs.h"
 
 static GdkColor quote_colors[3] = {
        {(gulong)0, (gushort)0, (gushort)0, (gushort)0},
@@ -943,10 +945,16 @@ void textview_show_mime_part(TextView *textview, MimeInfo *partinfo)
        GtkTextBuffer *buffer;
        GtkTextIter iter;
        const gchar *name;
-       gchar *content_type;
+       gchar *content_type, *shortcut;
+       GtkUIManager *ui_manager;
 
        if (!partinfo) return;
 
+       if (textview->messageview->window != NULL)
+               ui_manager = textview->messageview->ui_manager;
+       else
+               ui_manager = textview->messageview->mainwin->ui_manager;
+
        textview_set_font(textview, NULL);
        textview_clear(textview);
 
@@ -981,7 +989,11 @@ void textview_show_mime_part(TextView *textview, MimeInfo *partinfo)
        TEXTVIEW_INSERT(_("     - To save, select "));
        TEXTVIEW_INSERT_LINK(_("'Save as...'"), "sc://save_as", NULL);
 #ifndef GENERIC_UMPC
-       TEXTVIEW_INSERT(_(" (Shortcut key: 'y')"));
+       TEXTVIEW_INSERT(_(" (Shortcut key: '"));
+       shortcut = cm_menu_item_get_shortcut(ui_manager, "Menu/File/SavePartAs");
+       TEXTVIEW_INSERT(shortcut);
+       g_free(shortcut);
+       TEXTVIEW_INSERT("')");
 #endif
        TEXTVIEW_INSERT("\n");
 
@@ -989,7 +1001,11 @@ void textview_show_mime_part(TextView *textview, MimeInfo *partinfo)
        TEXTVIEW_INSERT_LINK(_("'Display as text'"), "sc://display_as_text", NULL);
 
 #ifndef GENERIC_UMPC
-       TEXTVIEW_INSERT(_(" (Shortcut key: 't')"));
+       TEXTVIEW_INSERT(_(" (Shortcut key: '"));
+       shortcut = cm_menu_item_get_shortcut(ui_manager, "Menu/View/Part/AsText");
+       TEXTVIEW_INSERT(shortcut);
+       g_free(shortcut);
+       TEXTVIEW_INSERT("')");
 #endif
        TEXTVIEW_INSERT("\n");
 
@@ -997,13 +1013,21 @@ void textview_show_mime_part(TextView *textview, MimeInfo *partinfo)
        TEXTVIEW_INSERT_LINK(_("'Open'"), "sc://open", NULL);
 
 #ifndef GENERIC_UMPC
-       TEXTVIEW_INSERT(_(" (Shortcut key: 'l')\n"));
+       TEXTVIEW_INSERT(_(" (Shortcut key: '"));
+       shortcut = cm_menu_item_get_shortcut(ui_manager, "Menu/View/Part/Open");
+       TEXTVIEW_INSERT(shortcut);
+       g_free(shortcut);
+       TEXTVIEW_INSERT("')\n");
        TEXTVIEW_INSERT(_("       (alternately double-click, or click the middle "));
        TEXTVIEW_INSERT(_("mouse button)\n"));
 #ifndef G_OS_WIN32
        TEXTVIEW_INSERT(_("     - Or use "));
        TEXTVIEW_INSERT_LINK(_("'Open with...'"), "sc://open_with", NULL);
-       TEXTVIEW_INSERT(_(" (Shortcut key: 'o')"));
+       TEXTVIEW_INSERT(_(" (Shortcut key: '"));
+       shortcut = cm_menu_item_get_shortcut(ui_manager, "Menu/View/Part/OpenWith");
+       TEXTVIEW_INSERT(shortcut);
+       g_free(shortcut);
+       TEXTVIEW_INSERT("')");
 #endif
 #endif
        TEXTVIEW_INSERT("\n");
@@ -1287,7 +1311,8 @@ static void textview_make_clickable_parts(TextView *textview,
        GtkTextView *text = GTK_TEXT_VIEW(textview->text);
        GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
        GtkTextIter iter;
-       gchar *mybuf = g_strdup(linebuf);
+       gint mybuf_len = strlen(linebuf);
+       gchar *mybuf = g_strndup(linebuf, mybuf_len);
        
        /* parse table - in order of priority */
        struct table {
@@ -1295,6 +1320,7 @@ static void textview_make_clickable_parts(TextView *textview,
 
                /* token search function */
                gchar    *(*search)     (const gchar *haystack,
+                                        gint  haystack_len,
                                         const gchar *needle);
                /* part parsing function */
                gboolean  (*parse)      (const gchar *start,
@@ -1308,14 +1334,14 @@ static void textview_make_clickable_parts(TextView *textview,
        };
 
        static struct table parser[] = {
-               {"http://",  strcasestr, get_uri_part,   make_uri_string},
-               {"https://", strcasestr, get_uri_part,   make_uri_string},
-               {"ftp://",   strcasestr, get_uri_part,   make_uri_string},
-               {"sftp://",  strcasestr, get_uri_part,   make_uri_string},
-               {"gopher://",strcasestr, get_uri_part,   make_uri_string},
-               {"www.",     strcasestr, get_uri_part,   make_http_string},
-               {"mailto:",  strcasestr, get_uri_part,   make_uri_string},
-               {"@",        strcasestr, get_email_part, make_email_string}
+               {"http://",  strncasestr, get_uri_part,   make_uri_string},
+               {"https://", strncasestr, get_uri_part,   make_uri_string},
+               {"ftp://",   strncasestr, get_uri_part,   make_uri_string},
+               {"sftp://",  strncasestr, get_uri_part,   make_uri_string},
+               {"gopher://",strncasestr, get_uri_part,   make_uri_string},
+               {"www.",     strncasestr, get_uri_part,   make_http_string},
+               {"mailto:",  strncasestr, get_uri_part,   make_uri_string},
+               {"@",        strncasestr, get_email_part, make_email_string}
        };
        const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
 
@@ -1330,51 +1356,50 @@ static void textview_make_clickable_parts(TextView *textview,
 
        if (!g_utf8_validate(linebuf, -1, NULL)) {
                g_free(mybuf);
-               mybuf = g_malloc(strlen(linebuf)*2 +1);
-               conv_localetodisp(mybuf, strlen(linebuf)*2 +1, linebuf);
+               mybuf = g_malloc(mybuf_len*2 +1);
+               conv_localetodisp(mybuf, mybuf_len*2 +1, linebuf);
+               mybuf_len = strlen(mybuf);
        }
 
        gtk_text_buffer_get_end_iter(buffer, &iter);
 
        /* parse for clickable parts, and build a list of begin and end positions  */
-       for (walk = mybuf, n = 0;;) {
-               gint last_index = PARSE_ELEMS;
-               gchar *scanpos = NULL;
-
-               /* FIXME: this looks phony. scanning for anything in the parse table */
-               for (n = 0; n < PARSE_ELEMS; n++) {
-                       gchar *tmp;
-
-                       tmp = parser[n].search(walk, parser[n].needle);
-                       if (tmp) {
-                               if (scanpos == NULL || tmp < scanpos) {
-                                       scanpos = tmp;
-                                       last_index = n;
-                               }
-                       }                                       
-               }
-
-               if (scanpos) {
-                       /* check if URI can be parsed */
-                       if (parser[last_index].parse(walk, scanpos, &bp, &ep, hdr)
-                           && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
-                                       ADD_TXT_POS(bp, ep, last_index);
+       for (n = 0; n < PARSE_ELEMS; n++) {
+               gint len = mybuf_len;
+               gint needle_len = strlen(parser[n].needle);
+               for (walk = mybuf;;) {
+                       gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
+                       if (scanpos) {
+                               /* check if URI can be parsed */
+                               if (parser[n].parse(walk, scanpos, &bp, &ep, hdr)
+                                               && (size_t) (ep - bp - 1) > needle_len) {
+                                       ADD_TXT_POS(bp, ep, n);
+                                       len -= ep - walk;
                                        walk = ep;
+                               } else {
+                                       len -= (scanpos + needle_len) - walk;
+                                       walk = scanpos + needle_len;
+                               }
                        } else
-                               walk = scanpos +
-                                       strlen(parser[last_index].needle);
-               } else
-                       break;
+                               break;
+               }
        }
 
        /* colorize this line */
        if (head.next) {
                const gchar *normal_text = mybuf;
+               struct txtpos *previous = NULL;
 
                /* insert URIs */
                for (last = head.next; last != NULL;
                     normal_text = last->ep, last = last->next) {
                        ClickableText *uri;
+
+                       if (previous != NULL
+                           && previous->bp < last->bp 
+                           && previous->ep == last->ep)
+                               continue;
+
                        uri = g_new0(ClickableText, 1);
                        if (last->bp - normal_text > 0)
                                gtk_text_buffer_insert_with_tags_by_name
@@ -1392,6 +1417,7 @@ static void textview_make_clickable_parts(TextView *textview,
                        uri->filename = NULL;
                        textview->uri_list =
                                g_slist_prepend(textview->uri_list, uri);
+                       previous = last;
                }
 
                if (*normal_text)
@@ -1412,6 +1438,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
        GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
        GtkTextIter start_iter, end_iter;
        gchar *mybuf;
+       gint mybuf_len;
        gint offset = 0;
        /* parse table - in order of priority */
        struct table {
@@ -1419,6 +1446,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
 
                /* token search function */
                gchar    *(*search)     (const gchar *haystack,
+                                        gint  haystack_len,
                                         const gchar *needle);
                /* part parsing function */
                gboolean  (*parse)      (const gchar *start,
@@ -1432,13 +1460,13 @@ static void textview_make_clickable_parts_later(TextView *textview,
        };
 
        static struct table parser[] = {
-               {"http://",  strcasestr, get_uri_part,   make_uri_string},
-               {"https://", strcasestr, get_uri_part,   make_uri_string},
-               {"ftp://",   strcasestr, get_uri_part,   make_uri_string},
-               {"sftp://",  strcasestr, get_uri_part,   make_uri_string},
-               {"www.",     strcasestr, get_uri_part,   make_http_string},
-               {"mailto:",  strcasestr, get_uri_part,   make_uri_string},
-               {"@",        strcasestr, get_email_part, make_email_string}
+               {"http://",  strncasestr, get_uri_part,   make_uri_string},
+               {"https://", strncasestr, get_uri_part,   make_uri_string},
+               {"ftp://",   strncasestr, get_uri_part,   make_uri_string},
+               {"sftp://",  strncasestr, get_uri_part,   make_uri_string},
+               {"www.",     strncasestr, get_uri_part,   make_http_string},
+               {"mailto:",  strncasestr, get_uri_part,   make_uri_string},
+               {"@",        strncasestr, get_email_part, make_email_string}
        };
        const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
 
@@ -1457,44 +1485,43 @@ static void textview_make_clickable_parts_later(TextView *textview,
        offset = gtk_text_iter_get_offset(&start_iter);
 
        /* parse for clickable parts, and build a list of begin and end positions  */
-       for (walk = mybuf, n = 0;;) {
-               gint last_index = PARSE_ELEMS;
-               gchar *scanpos = NULL;
-
-               /* FIXME: this looks phony. scanning for anything in the parse table */
-               for (n = 0; n < PARSE_ELEMS; n++) {
-                       gchar *tmp;
-
-                       tmp = parser[n].search(walk, parser[n].needle);
-                       if (tmp) {
-                               if (scanpos == NULL || tmp < scanpos) {
-                                       scanpos = tmp;
-                                       last_index = n;
-                               }
-                       }                                       
-               }
-
-               if (scanpos) {
-                       /* check if URI can be parsed */
-                       if (parser[last_index].parse(walk, scanpos, &bp, &ep, FALSE)
-                           && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
-                                       ADD_TXT_POS_LATER(bp, ep, last_index);
+       mybuf_len = strlen(mybuf);
+       for (n = 0; n < PARSE_ELEMS; n++) {
+               gint len = mybuf_len;
+               gint needle_len = strlen(parser[n].needle);
+               for (walk = mybuf;;) {
+                       gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
+                       if (scanpos) {
+                               /* check if URI can be parsed */
+                               if (parser[n].parse(walk, scanpos, &bp, &ep, FALSE)
+                                               && (size_t) (ep - bp - 1) > needle_len) {
+                                       ADD_TXT_POS_LATER(bp, ep, n);
+                                       len -= ep - walk;
                                        walk = ep;
+                               } else {
+                                       len -= (scanpos + needle_len) - walk;
+                                       walk = scanpos + needle_len;
+                               }
                        } else
-                               walk = scanpos +
-                                       strlen(parser[last_index].needle);
-               } else
-                       break;
+                               break;
+               }
        }
 
        /* colorize this line */
        if (head.next) {
+               struct txtpos *previous = NULL;
                /* insert URIs */
                for (last = head.next; last != NULL; last = last->next) {
                        ClickableText *uri;
                        gint start_offset, end_offset;
                        gchar *tmp_str;
                        gchar old_char;
+
+                       if (previous != NULL
+                           && previous->bp < last->bp 
+                           && previous->ep == last->ep)
+                               continue;
+
                        uri = g_new0(ClickableText, 1);
                        uri->uri = parser[last->pti].build_uri(last->bp,
                                                               last->ep);
@@ -1521,6 +1548,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
                        uri->filename = NULL;
                        textview->uri_list =
                                g_slist_prepend(textview->uri_list, uri);
+                       previous = last;
                }
        } 
 
@@ -1613,6 +1641,7 @@ do_quote:
                        uri = g_new0(ClickableText, 1);
                        uri->uri = g_strdup("");
                        uri->data = g_strdup(buf);
+                       uri->data_len = strlen(uri->data);
                        uri->start = gtk_text_iter_get_offset(&iter);
                        uri->is_quote = TRUE;
                        uri->quote_level = real_quotelevel;
@@ -1645,11 +1674,12 @@ do_quote:
                                        textview->prev_quote_level = -1;
                                        goto do_quote;
                                }
-                               e_len = lasturi->data ? strlen(lasturi->data):0;
+                               e_len = lasturi->data ? lasturi->data_len:0;
                                n_len = strlen(buf);
                                lasturi->data = g_realloc((gchar *)lasturi->data, e_len + n_len + 1);
                                strcpy((gchar *)lasturi->data + e_len, buf);
                                *((gchar *)lasturi->data + e_len + n_len) = '\0';
+                               lasturi->data_len += n_len;
                        }
                }
        } else {
@@ -1661,7 +1691,6 @@ do_quote:
 void textview_write_link(TextView *textview, const gchar *str,
                         const gchar *uri, CodeConverter *conv)
 {
-       GdkColor *link_color = NULL;
        GtkTextView *text;
        GtkTextBuffer *buffer;
        GtkTextIter iter;
@@ -1702,9 +1731,6 @@ void textview_write_link(TextView *textview, const gchar *str,
        if (bufp > buf)
                gtk_text_buffer_insert(buffer, &iter, buf, bufp - buf);
 
-       if (prefs_common.enable_color) {
-               link_color = &uri_color;
-       }
        r_uri = g_new0(ClickableText, 1);
        r_uri->uri = g_strdup(uri);
        r_uri->start = gtk_text_iter_get_offset(&iter);
@@ -2426,19 +2452,6 @@ static gint textview_key_pressed(GtkWidget *widget, GdkEventKey *event,
                if (summaryview)
                        summary_pass_key_press_event(summaryview, event);
                break;
-       case GDK_KEY_y:
-       case GDK_KEY_t:
-       case GDK_KEY_l:
-       case GDK_KEY_o:
-       case GDK_KEY_c:
-       case GDK_KEY_a:
-               if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0) {
-                       KEY_PRESS_EVENT_STOP();
-                       mimeview_pass_key_press_event(messageview->mimeview,
-                                                     event);
-                       break;
-               }
-               /* possible fall through */
        default:
                window = gtk_widget_get_window(messageview->mainwin->window);
                if (summaryview &&
@@ -3060,6 +3073,8 @@ static void save_file_cb (GtkAction *action, TextView *textview)
        gchar *filepath = NULL;
        gchar *filedir = NULL;
        gchar *tmp_filename = NULL;
+       GtkWidget *window;
+
        if (uri == NULL)
                return;
 
@@ -3084,6 +3099,14 @@ static void save_file_cb (GtkAction *action, TextView *textview)
 
        g_free(filename);
 
+       /* Pick correct window to set the file dialog "transient for" */
+       if (textview->messageview->window != NULL)
+               window = textview->messageview->window;
+       else
+               window = textview->messageview->mainwin->window;
+
+       manage_window_focus_in(window, NULL, NULL);
+
        filename = filesel_select_file_save(_("Save as"), filepath);
        if (!filename) {
                g_free(filepath);