sync with sylpheed 0.6.4cvs1
[claws.git] / src / textview.c
index 9a37ddb279364d4cb2661e9742ec668e8642a4a5..130e4fb5ce74e3511553458c740485e326e05144 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999,2000 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2001 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -151,6 +151,8 @@ TextView *textview_create(void)
        /* create GtkText widgets for single-byte and multi-byte character */
        text_sb = gtk_text_new(NULL, NULL);
        text_mb = gtk_text_new(NULL, NULL);
+       GTK_TEXT(text_sb)->default_tab_width = 8;
+       GTK_TEXT(text_mb)->default_tab_width = 8;
        gtk_widget_show(text_sb);
        gtk_widget_show(text_mb);
        gtk_text_set_word_wrap(GTK_TEXT(text_sb), TRUE);
@@ -181,15 +183,15 @@ TextView *textview_create(void)
        gtk_signal_connect(GTK_OBJECT(text_sb), "key_press_event",
                           GTK_SIGNAL_FUNC(textview_key_pressed),
                           textview);
-       gtk_signal_connect(GTK_OBJECT(text_sb), "button_press_event",
-                          GTK_SIGNAL_FUNC(textview_button_pressed),
-                          textview);
+       gtk_signal_connect_after(GTK_OBJECT(text_sb), "button_press_event",
+                                GTK_SIGNAL_FUNC(textview_button_pressed),
+                                textview);
        gtk_signal_connect(GTK_OBJECT(text_mb), "key_press_event",
                           GTK_SIGNAL_FUNC(textview_key_pressed),
                           textview);
-       gtk_signal_connect(GTK_OBJECT(text_mb), "button_press_event",
-                          GTK_SIGNAL_FUNC(textview_button_pressed),
-                          textview);
+       gtk_signal_connect_after(GTK_OBJECT(text_mb), "button_press_event",
+                                GTK_SIGNAL_FUNC(textview_button_pressed),
+                                textview);
 
        gtk_widget_show(scrolledwin_sb);
        gtk_widget_show(scrolledwin_mb);
@@ -206,6 +208,8 @@ TextView *textview_create(void)
        textview->text_mb        = text_mb;
        textview->text_is_mb     = FALSE;
        textview->uri_list       = NULL;
+       textview->body_pos       = 0;
+       textview->cur_pos        = 0;
 
        return textview;
 }
@@ -307,11 +311,13 @@ void textview_show_part(TextView *textview, MimeInfo *mimeinfo, FILE *fp)
 
        /* display attached RFC822 single text message */
        if (mimeinfo->parent && mimeinfo->mime_type == MIME_MESSAGE_RFC822) {
+               if (headers) procheader_header_array_destroy(headers);
                if (!mimeinfo->sub || mimeinfo->sub->children) return;
                headers = textview_scan_header(textview, fp);
                mimeinfo = mimeinfo->sub;
        } else if (!mimeinfo->parent &&
                   mimeinfo->mime_type == MIME_MESSAGE_RFC822) {
+               if (headers) procheader_header_array_destroy(headers);
                if (!mimeinfo->sub) return;
                headers = textview_scan_header(textview, fp);
                mimeinfo = mimeinfo->sub;
@@ -329,9 +335,12 @@ void textview_show_part(TextView *textview, MimeInfo *mimeinfo, FILE *fp)
        text = GTK_TEXT(textview->text);
        gtk_text_freeze(text);
 
+       textview->body_pos = 0;
+       textview->cur_pos  = 0;
+
        if (headers) {
                textview_show_header(textview, headers);
-               procheader_header_array_destroy(headers);               
+               procheader_header_array_destroy(headers);
        }
 
        tmpfp = procmime_decode_content(NULL, fp, mimeinfo);
@@ -473,6 +482,8 @@ static gchar *make_uri_string(const gchar *bp, const gchar *ep)
         !isspace(ch) && \
         !strchr("()<>\"", (ch)))
 
+#define IS_QUOTE(ch) ((ch) == '\'' || (ch) == '"')
+
 /* get_email_part() - retrieves an email address. Returns TRUE if succesful */
 static gboolean get_email_part(const gchar *start, const gchar *scanpos,
                               const gchar **bp, const gchar **ep)
@@ -522,9 +533,11 @@ static gboolean get_email_part(const gchar *start, const gchar *scanpos,
 
        if (!result) return FALSE;
 
-       /* we now have at least the address. now see if this is <bracketed>; in this
-        * case we also scan for the informative part. we could make this a useful
-        * function because it tries to parse out an email address backwards. :) */
+       /* skip if it's between quotes "'alfons@proteus.demon.nl'" <alfons@proteus.demon.nl> */
+       if (bp_ - 1 > start && IS_QUOTE(*(bp_ - 1)) && IS_QUOTE(*ep_)) 
+               return FALSE;
+
+       /* see if this is <bracketed>; in this case we also scan for the informative part. */
        if (bp_ - 1 <= start || *(bp_ - 1) != '<' || *ep_ != '>')
                return TRUE;
 
@@ -588,6 +601,7 @@ static gboolean get_email_part(const gchar *start, const gchar *scanpos,
        return result;
 }
 
+#undef IS_QUOTE
 #undef IS_RFC822_CHAR
 
 static gchar *make_email_string(const gchar *bp, const gchar *ep)
@@ -618,7 +632,7 @@ static gchar *make_email_string(const gchar *bp, const gchar *ep)
 
 /* textview_make_clickable_parts() - colorizes clickable parts */
 static void textview_make_clickable_parts(TextView *textview,
-                                         GdkFont  *font,
+                                         GdkFont *font,
                                          GdkColor *fg_color,
                                          GdkColor *uri_color,
                                          const gchar *linebuf)
@@ -707,7 +721,7 @@ static void textview_make_clickable_parts(TextView *textview,
                                                normal_text,
                                                last->bp - normal_text);
                        uri->uri = parser[last->pti].build_uri(last->bp, 
-                                               last->ep);
+                                                              last->ep);
                        uri->start = gtk_text_get_point(text);
                        gtk_text_insert(text, font, uri_color,
                                        NULL, last->bp, last->ep - last->bp);
@@ -782,8 +796,8 @@ static void textview_write_line(TextView *textview, const gchar *str,
                textview_make_clickable_parts(textview, textview->msgfont,
                                              fg_color, &uri_color, buf);
        else
-               gtk_text_insert(text, textview->msgfont, fg_color, NULL,
-                               buf, -1);
+               textview_make_clickable_parts(textview, textview->msgfont,
+                                             fg_color, NULL, buf);
 }
 
 void textview_clear(TextView *textview)
@@ -791,7 +805,8 @@ void textview_clear(TextView *textview)
        GtkText *text = GTK_TEXT(textview->text);
 
        gtk_text_freeze(text);
-       gtk_text_backward_delete(text, gtk_text_get_length(text));
+       gtk_text_set_point(text, 0);
+       gtk_text_forward_delete(text, gtk_text_get_length(text));
        gtk_text_thaw(text);
 
        textview_uri_list_remove_all(textview->uri_list);
@@ -828,11 +843,13 @@ void textview_set_font(TextView *textview, const gchar *codeset)
        if (MB_CUR_MAX > 1) {
                if (codeset) {
                        if (!g_strncasecmp(codeset, "ISO-8859-", 9) ||
-                           !g_strncasecmp(codeset, "KOI8-", 5)     ||
-                           !g_strncasecmp(codeset, "CP", 2)        ||
-                           !g_strncasecmp(codeset, "WINDOWS-", 8)  ||
                            !g_strcasecmp(codeset, "BALTIC"))
                                use_fontset = FALSE;
+                       else if (conv_get_current_charset() != C_EUC_JP &&
+                                (!g_strncasecmp(codeset, "KOI8-", 5) ||
+                                 !g_strncasecmp(codeset, "CP", 2)    ||
+                                 !g_strncasecmp(codeset, "WINDOWS-", 8)))
+                               use_fontset = FALSE;
                }
        } else
                use_fontset = FALSE;
@@ -919,15 +936,23 @@ enum
        H_ORGANIZATION  = 11,
 };
 
+void textview_set_position(TextView *textview, gint pos)
+{
+       if (pos < 0) {
+               textview->cur_pos =
+                       gtk_text_get_length(GTK_TEXT(textview->text));
+       } else {
+               textview->cur_pos = pos;
+       }
+}
+
 static GPtrArray *textview_scan_header(TextView *textview, FILE *fp)
 {
        gchar buf[BUFFSIZE];
        GPtrArray *headers, *sorted_headers;
        GSList *disphdr_list;
        Header *header;
-       guint i;
-
-       textview = textview;
+       gint i;
 
        g_return_val_if_fail(fp != NULL, NULL);
 
@@ -969,7 +994,8 @@ static GPtrArray *textview_scan_header(TextView *textview, FILE *fp)
                }
        }
 
-       g_ptr_array_free(headers, TRUE);
+       g_ptr_array_free(headers, FALSE);
+
        return sorted_headers;
 }
 
@@ -977,7 +1003,7 @@ static void textview_show_header(TextView *textview, GPtrArray *headers)
 {
        GtkText *text = GTK_TEXT(textview->text);
        Header *header;
-       guint i;
+       gint i;
 
        g_return_if_fail(headers != NULL);
 
@@ -989,7 +1015,9 @@ static void textview_show_header(TextView *textview, GPtrArray *headers)
 
                gtk_text_insert(text, textview->boldfont, NULL, NULL,
                                header->name, -1);
-               gtk_text_insert(text, textview->boldfont, NULL, NULL, " ", 1);
+               if (header->name[strlen(header->name) - 1] != ' ')
+                       gtk_text_insert(text, textview->boldfont,
+                                       NULL, NULL, " ", 1);
 
                if (procheader_headername_equal(header->name, "Subject") ||
                    procheader_headername_equal(header->name, "From")    ||
@@ -1009,14 +1037,100 @@ static void textview_show_header(TextView *textview, GPtrArray *headers)
                                                      NULL, NULL, &uri_color,
                                                      header->body);
                } else {
-                       gtk_text_insert(text, NULL, NULL, NULL,
-                                       header->body, -1);
+                       textview_make_clickable_parts(textview,
+                                                     NULL, NULL, NULL,
+                                                     header->body);
                }
                gtk_text_insert(text, textview->msgfont, NULL, NULL, "\n", 1);
        }
 
        gtk_text_insert(text, textview->msgfont, NULL, NULL, "\n", 1);
        gtk_text_thaw(text);
+       textview->body_pos = gtk_text_get_length(text);
+}
+
+gboolean textview_search_string(TextView *textview, const gchar *str,
+                               gboolean case_sens)
+{
+       GtkText *text = GTK_TEXT(textview->text);
+       gint pos;
+       wchar_t *wcs;
+       gint len;
+       gint text_len;
+       gboolean found = FALSE;
+
+       g_return_val_if_fail(str != NULL, FALSE);
+
+       wcs = strdup_mbstowcs(str);
+       g_return_val_if_fail(wcs != NULL, FALSE);
+       len = wcslen(wcs);
+       pos = textview->cur_pos;
+       if (pos < textview->body_pos)
+               pos = textview->body_pos;
+       text_len = gtk_text_get_length(text);
+       if (text_len - pos < len) {
+               g_free(wcs);
+               return FALSE;
+       }
+
+       for (; pos < text_len; pos++) {
+               if (text_len - pos < len) break;
+               if (gtkut_text_match_string(text, pos, wcs, len, case_sens)
+                   == TRUE) {
+                       gtk_editable_set_position(GTK_EDITABLE(text),
+                                                 pos + len);
+                       gtk_editable_select_region(GTK_EDITABLE(text),
+                                                  pos, pos + len);
+                       textview_set_position(textview, pos + len);
+                       found = TRUE;
+                       break;
+               }
+               if (text_len - pos == len) break;
+       }
+
+       g_free(wcs);
+       return found;
+}
+
+gboolean textview_search_string_backward(TextView *textview, const gchar *str,
+                                        gboolean case_sens)
+{
+       GtkText *text = GTK_TEXT(textview->text);
+       gint pos;
+       wchar_t *wcs;
+       gint len;
+       gint text_len;
+       gboolean found = FALSE;
+
+       g_return_val_if_fail(str != NULL, FALSE);
+
+       wcs = strdup_mbstowcs(str);
+       g_return_val_if_fail(wcs != NULL, FALSE);
+       len = wcslen(wcs);
+       pos = textview->cur_pos;
+       text_len = gtk_text_get_length(text);
+       if (text_len - textview->body_pos < len) {
+               g_free(wcs);
+               return FALSE;
+       }
+       if (pos <= textview->body_pos || text_len - pos < len)
+               pos = text_len - len;
+
+       for (; pos >= textview->body_pos; pos--) {
+               if (gtkut_text_match_string(text, pos, wcs, len, case_sens)
+                   == TRUE) {
+                       gtk_editable_set_position(GTK_EDITABLE(text), pos);
+                       gtk_editable_select_region(GTK_EDITABLE(text),
+                                                  pos, pos + len);
+                       textview_set_position(textview, pos - 1);
+                       found = TRUE;
+                       break;
+               }
+               if (pos == textview->body_pos) break;
+       }
+
+       g_free(wcs);
+       return found;
 }
 
 void textview_scroll_one_line(TextView *textview, gboolean up)
@@ -1197,8 +1311,6 @@ static void textview_key_pressed(GtkWidget *widget, GdkEventKey *event,
 {
        SummaryView *summaryview = NULL;
 
-       widget = widget;
-
        if (!event) return;
        if (textview->messageview->mainwin)
                summaryview = textview->messageview->mainwin->summaryview;
@@ -1240,21 +1352,19 @@ static void textview_key_pressed(GtkWidget *widget, GdkEventKey *event,
 static void textview_button_pressed(GtkWidget *widget, GdkEventButton *event,
                                    TextView *textview)
 {
-       widget = widget;
+       textview->cur_pos = 
+               gtk_editable_get_position(GTK_EDITABLE(textview->text));
+
        if (event &&
-           ((event->button == 1 && event->type == GDK_2BUTTON_PRESS) 
-               || event->button == 2
-               || event->button == 3)) {
+           ((event->button == 1 && event->type == GDK_2BUTTON_PRESS)
+            || event->button == 2 || event->button == 3)) {
                GSList *cur;
-               guint current_pos;
-
-               current_pos = GTK_EDITABLE(textview->text)->current_pos;
 
                for (cur = textview->uri_list; cur != NULL; cur = cur->next) {
                        RemoteURI *uri = (RemoteURI *)cur->data;
 
-                       if (current_pos >= uri->start &&
-                           current_pos <  uri->end) {
+                       if (textview->cur_pos >= uri->start &&
+                           textview->cur_pos <  uri->end) {
                                if (!g_strncasecmp(uri->uri, "mailto:", 7)) {
                                        if (event->button == 3) {
                                                gchar *fromname, *fromaddress;
@@ -1264,19 +1374,19 @@ static void textview_button_pressed(GtkWidget *widget, GdkEventButton *event,
                                                fromname = procheader_get_fromname(fromaddress);
                                                extract_address(fromaddress);
                                                g_message("adding from textview %s <%s>", fromname, fromaddress);
-                                               addressbook_add_contact_by_menu(NULL, fromname, fromaddress, NULL);
+                                               // Add to address book - Match
+                                               addressbook_add_contact( fromname, fromaddress, NULL );
                                                g_free(fromaddress);
                                                g_free(fromname);
-                                       }
-                                       else {
+                                       } else {
                                                compose_new_with_recipient
                                                        (NULL, uri->uri + 7);
-                                       }               
-                               }                                               
-                               else
+                                       }
+                               } else {
                                        open_uri(uri->uri,
                                                 prefs_common.uri_cmd);
-                       }                               
+                               }
+                       }
                }
        }
 }