balsa r7839 - in trunk: . libbalsa src



Author: PeterB
Date: Fri Feb  8 03:57:27 2008
New Revision: 7839
URL: http://svn.gnome.org/viewvc/balsa?rev=7839&view=rev

Log:
find in message

Modified:
   trunk/ChangeLog
   trunk/libbalsa/libbalsa.c
   trunk/src/balsa-message.c
   trunk/src/balsa-message.h
   trunk/src/main-window.c

Modified: trunk/libbalsa/libbalsa.c
==============================================================================
--- trunk/libbalsa/libbalsa.c	(original)
+++ trunk/libbalsa/libbalsa.c	Fri Feb  8 03:57:27 2008
@@ -750,7 +750,9 @@
     self = pthread_self();
 
     if (libbalsa_threads_lock == 0 || self != libbalsa_threads_id) {
-	g_warning("Not holding gdk lock!!!");
+#if WARN_ABOUT_THREADS_ERRORS
+        g_warning("%s: Not holding gdk lock!!!", __func__);
+#endif                          /* WARN_ABOUT_THREADS_ERRORS */
 	return;
     }
 

Modified: trunk/src/balsa-message.c
==============================================================================
--- trunk/src/balsa-message.c	(original)
+++ trunk/src/balsa-message.c	Fri Feb  8 03:57:27 2008
@@ -368,9 +368,246 @@
     gtk_container_foreach (GTK_CONTAINER(widget), balsa_mime_widget_image_resize_all, NULL);
 }
 
+/*
+ * Callbacks and helpers for the find bar.
+ */
+
+static void
+bm_scroll_to_iter(BalsaMessage * bm, GtkTextView * text_view,
+                  GtkTextIter * iter)
+{
+    GtkAdjustment *adj = GTK_VIEWPORT(bm->cont_viewport)->vadjustment;
+    GdkRectangle location;
+    gdouble y;
+
+    gtk_text_view_get_iter_location(text_view, iter, &location);
+    gtk_text_view_buffer_to_window_coords(text_view,
+                                          GTK_TEXT_WINDOW_WIDGET,
+                                          location.x, location.y,
+                                          NULL, &location.y);
+    gtk_widget_translate_coordinates(GTK_WIDGET(text_view),
+                                     bm->bm_widget->widget,
+                                     location.x, location.y,
+                                     NULL, &location.y);
+
+    y = location.y;
+    gtk_adjustment_clamp_page(adj, y - adj->step_increment,
+                                   y + adj->step_increment);
+}
+
+static void
+bm_find_entry_changed_cb(GtkEditable * editable, gpointer data)
+{
+    GtkEntry *entry = GTK_ENTRY(editable);
+    const gchar *text = gtk_entry_get_text(entry);
+    BalsaMessage *bm = data;
+    GtkWidget *w = bm->current_part->mime_widget->widget;
+    GtkTextBuffer *buffer = gtk_text_view_get_buffer((GtkTextView *) w);
+    GtkTextIter match_begin, match_end;
+    gboolean found;
+
+    if (bm->find_forward) {
+        found = gtk_text_iter_forward_search(&bm->find_iter, text, 0,
+                                             &match_begin, &match_end,
+                                             NULL);
+        if (!found) {
+            /* Silently wrap to the top. */
+            gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+            found = gtk_text_iter_forward_search(&bm->find_iter, text, 0,
+                                                 &match_begin, &match_end,
+                                                 NULL);
+            gdk_threads_enter();        /* Just a guess! */
+        }
+    } else {
+        found = gtk_text_iter_backward_search(&bm->find_iter, text, 0,
+                                              &match_begin, &match_end,
+                                              NULL);
+        if (!found) {
+            /* Silently wrap to the bottom. */
+            gtk_text_buffer_get_end_iter(buffer, &bm->find_iter);
+            found = gtk_text_iter_backward_search(&bm->find_iter, text, 0,
+                                                  &match_begin, &match_end,
+                                                  NULL);
+            gdk_threads_enter();        /* Just a guess! */
+        }
+    }
+
+    if (found) {
+        gtk_widget_hide(bm->find_sep);
+        gtk_widget_hide(bm->find_label);
+        gtk_widget_set_sensitive(bm->find_prev, TRUE);
+        gtk_widget_set_sensitive(bm->find_next, TRUE);
+        gtk_text_buffer_select_range(buffer, &match_begin, &match_end);
+        bm_scroll_to_iter(bm, (GtkTextView *) w, &match_begin);
+        bm->find_iter = match_begin;
+    } else {
+        gtk_label_set_text(GTK_LABEL(bm->find_label), _("Not found"));
+        gtk_widget_show(bm->find_sep);
+        gtk_widget_show(bm->find_label);
+        gtk_widget_set_sensitive(bm->find_prev, FALSE);
+        gtk_widget_set_sensitive(bm->find_next, FALSE);
+    }
+}
+
+static void
+bm_find_again(BalsaMessage * bm, gboolean find_forward)
+{
+    const gchar *text = gtk_entry_get_text(GTK_ENTRY(bm->find_entry));
+    GtkTextIter match_begin, match_end;
+    GtkWidget *w = bm->current_part->mime_widget->widget;
+    GtkTextBuffer *buffer = gtk_text_view_get_buffer((GtkTextView *) w);
+    gboolean found;
+
+    if (find_forward) {
+        gtk_text_iter_forward_char(&bm->find_iter);
+        found = gtk_text_iter_forward_search(&bm->find_iter, text, 0,
+                                             &match_begin, &match_end,
+                                             NULL);
+    } else {
+        gtk_text_iter_backward_char(&bm->find_iter);
+        found = gtk_text_iter_backward_search(&bm->find_iter, text, 0,
+                                              &match_begin, &match_end,
+                                              NULL);
+    }
+
+    if (found) {
+        gtk_widget_hide(bm->find_sep);
+        gtk_widget_hide(bm->find_label);
+    } else {
+        if (find_forward) {
+            gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+            gtk_text_iter_forward_search(&bm->find_iter, text, 0,
+                                         &match_begin, &match_end, NULL);
+        } else {
+            gtk_text_buffer_get_end_iter(buffer, &bm->find_iter);
+            gtk_text_iter_backward_search(&bm->find_iter, text, 0,
+                                          &match_begin, &match_end, NULL);
+        }
+        gtk_label_set_text(GTK_LABEL(bm->find_label),
+                           _("Wrapped"));
+        gtk_widget_show(bm->find_sep);
+        gtk_widget_show(bm->find_label);
+        gdk_threads_enter();        /* Just a guess! */
+    }
+
+    gtk_text_buffer_select_range(buffer, &match_begin, &match_end);
+    bm_scroll_to_iter(bm, (GtkTextView *) w, &match_begin);
+    bm->find_iter = match_begin;
+    bm->find_forward = find_forward;
+}
+
+static void
+bm_find_prev_cb(GtkToolButton * prev_button, gpointer data)
+{
+    bm_find_again((BalsaMessage *) data, FALSE);
+}
+
+static void
+bm_find_next_cb(GtkToolButton * prev_button, gpointer data)
+{
+    bm_find_again((BalsaMessage *) data, TRUE);
+}
+
+static GtkWidget *
+bm_find_bar_new(BalsaMessage * bm)
+{
+    GtkWidget *toolbar;
+    GtkWidget *hbox;
+    GtkToolItem *tool_item;
+
+    toolbar = gtk_toolbar_new();
+    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+
+    hbox = gtk_hbox_new(FALSE, 6);
+    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Find:")),
+                       FALSE, FALSE, 0);
+    bm->find_entry = gtk_entry_new();
+    g_signal_connect(bm->find_entry, "changed",
+                     G_CALLBACK(bm_find_entry_changed_cb), bm);
+    gtk_box_pack_start(GTK_BOX(hbox), bm->find_entry, FALSE, FALSE, 0);
+
+    tool_item = gtk_tool_item_new();
+    gtk_container_add(GTK_CONTAINER(tool_item), hbox);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    tool_item =
+        gtk_tool_button_new(gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE),
+                            _("Previous"));
+    bm->find_prev = GTK_WIDGET(tool_item);
+    gtk_tool_item_set_is_important(tool_item, TRUE);
+    g_signal_connect(tool_item, "clicked", G_CALLBACK(bm_find_prev_cb), bm);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    tool_item =
+        gtk_tool_button_new(gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE),
+                            _("Next"));
+    bm->find_next = GTK_WIDGET(tool_item);
+    gtk_tool_item_set_is_important(tool_item, TRUE);
+    g_signal_connect(tool_item, "clicked", G_CALLBACK(bm_find_next_cb), bm);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    bm->find_sep = GTK_WIDGET(gtk_separator_tool_item_new());
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(bm->find_sep), -1);
+
+    bm->find_label = gtk_label_new("");
+    tool_item = gtk_tool_item_new();
+    gtk_container_add(GTK_CONTAINER(tool_item), bm->find_label);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    gtk_widget_hide(toolbar);
+
+    return toolbar;
+}
+
+static gboolean bm_disable_find_entry(BalsaMessage * bm);
+
+static gboolean
+bm_pass_to_find_entry(BalsaMessage * bm, GdkEventKey * event)
+{
+    gboolean res = TRUE;
+
+    switch (event->keyval) {
+    case GDK_Escape:
+    case GDK_Return:
+    case GDK_KP_Enter:
+        bm_disable_find_entry(bm);
+        return res;
+    case GDK_g:
+        if (event->state == GDK_CONTROL_MASK) {
+            bm_find_again(bm, bm->find_forward);
+            return res;
+        }
+    default:
+        break;
+    }
+
+    res = FALSE;
+    if (GTK_WIDGET_HAS_FOCUS(bm->find_entry))
+        g_signal_emit_by_name(bm->find_entry, "key-press-event", event,
+                              &res, NULL);
+
+    return res;
+}
+
+static gboolean
+bm_disable_find_entry(BalsaMessage * bm)
+{
+    g_signal_handlers_disconnect_by_func
+        (gtk_widget_get_toplevel(GTK_WIDGET(bm)),
+         G_CALLBACK(bm_pass_to_find_entry), bm);
+    gtk_widget_hide(bm->find_bar);
+
+    return FALSE;
+}
+
+/*
+ * End of callbacks and helpers for the find bar.
+ */
+
 static void
 balsa_message_init(BalsaMessage * bm)
 {
+    GtkWidget *vbox;
     GtkWidget *scroll;
     GtkWidget *label;
     GtkTreeStore *model;
@@ -379,6 +616,11 @@
 
     gtk_notebook_set_show_border(GTK_NOTEBOOK(bm), FALSE);
 
+    /* Box to hold the scrolled window and the find bar */
+    vbox = gtk_vbox_new(FALSE, 0);
+    label = gtk_label_new(_("Content"));
+    gtk_notebook_append_page(GTK_NOTEBOOK(bm), vbox, label);
+
     /* scrolled window for the contents */
     bm->scroll = scroll = gtk_scrolled_window_new(NULL, NULL);
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
@@ -386,8 +628,7 @@
                                    GTK_POLICY_AUTOMATIC);
     g_signal_connect(scroll, "key_press_event",
 		     G_CALLBACK(balsa_mime_widget_key_press_event), bm);
-    label = gtk_label_new(_("Content"));
-    gtk_notebook_append_page(GTK_NOTEBOOK(bm), scroll, label);
+    gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
     bm->cont_viewport = gtk_viewport_new(NULL, NULL);
     gtk_container_add(GTK_CONTAINER(scroll), bm->cont_viewport);
     gtk_widget_show_all(scroll);
@@ -396,6 +637,10 @@
     g_signal_connect(bm->cont_viewport, "size-allocate",
 		     G_CALLBACK(on_content_size_alloc), NULL);
 
+    /* Find-in-message toolbar */
+    bm->find_bar = bm_find_bar_new(bm);
+    gtk_box_pack_start(GTK_BOX(vbox), bm->find_bar, FALSE, FALSE, 0);
+
     /* Widget to hold headers */
     bm->bm_widget = balsa_mime_widget_new_message_tl(bm, bm_header_tl_buttons(bm));
 
@@ -480,6 +725,9 @@
     bm->shown_headers = balsa_app.shown_headers;
     bm->show_all_headers = FALSE;
     bm->close_with_msg = FALSE;
+
+    gtk_widget_show_all(GTK_WIDGET(bm));
+    gtk_widget_hide(bm->find_bar);
 }
 
 static void
@@ -778,6 +1026,7 @@
     g_return_val_if_fail(bm != NULL, FALSE);
 
     gtk_widget_hide(GTK_WIDGET(bm));
+    bm_disable_find_entry(bm);
     select_part(bm, NULL);
     if (bm->message != NULL) {
         libbalsa_message_body_unref(bm->message);
@@ -2857,3 +3106,35 @@
 }
 
 #endif  /* HAVE_GPGME */
+
+/*
+ * Public method for find-in-message.
+ */
+
+void
+balsa_message_find_in_message(BalsaMessage * bm)
+{
+    GtkWidget *w;
+
+    if (bm->current_part
+        && (w = bm->current_part->mime_widget->widget)
+        && GTK_IS_TEXT_VIEW(w)) {
+        GtkTextBuffer *buffer = gtk_text_view_get_buffer((GtkTextView *) w);
+
+        bm->find_forward = TRUE;
+        gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+        gtk_entry_set_text(GTK_ENTRY(bm->find_entry), "");
+        g_signal_connect_swapped(gtk_widget_get_toplevel(GTK_WIDGET(bm)),
+                                 "key-press-event",
+                                 G_CALLBACK(bm_pass_to_find_entry), bm);
+
+        gtk_widget_hide(bm->find_sep);
+        gtk_widget_hide(bm->find_label);
+
+        gtk_widget_set_sensitive(bm->find_prev, FALSE);
+        gtk_widget_set_sensitive(bm->find_next, FALSE);
+
+        gtk_widget_show(bm->find_bar);
+        gtk_widget_grab_focus(bm->find_entry);
+    }
+}

Modified: trunk/src/balsa-message.h
==============================================================================
--- trunk/src/balsa-message.h	(original)
+++ trunk/src/balsa-message.h	Fri Feb  8 03:57:27 2008
@@ -80,6 +80,16 @@
 	gboolean close_with_msg;
 
         BalsaMessageFocusState focus_state;
+
+        /* Find-in-message stuff */
+        GtkWidget  *find_bar;
+        GtkWidget  *find_entry;
+        GtkWidget  *find_next;
+        GtkWidget  *find_prev;
+        GtkWidget  *find_sep;
+        GtkWidget  *find_label;
+        GtkTextIter find_iter;
+        gboolean    find_forward;
 };
 
 struct _BalsaMessageClass {
@@ -125,6 +135,8 @@
 				  guint max_ref);
 #endif
 
+void balsa_message_find_in_message (BalsaMessage * bm);
+
 #ifdef __cplusplus
 }
 #endif				/* __cplusplus */

Modified: trunk/src/main-window.c
==============================================================================
--- trunk/src/main-window.c	(original)
+++ trunk/src/main-window.c	Fri Feb  8 03:57:27 2008
@@ -194,6 +194,7 @@
 #if !defined(ENABLE_TOUCH_UI)
 static void bw_message_copy_cb            (GtkAction * action, gpointer data);
 static void bw_message_select_all_cb      (GtkAction * action, gpointer data);
+static void bw_find_in_message_cb         (GtkAction * action, gpointer data);
 #endif /* ENABLE_TOUCH_UI */
 static void bw_mark_all_cb                (GtkAction * action, gpointer data);
 
@@ -521,7 +522,10 @@
     {"CopyMessage", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
      N_("Copy message"), G_CALLBACK(bw_message_copy_cb)},
     {"SelectText", NULL, N_("_Select Text"), NULL,
-     N_("Select entire mail"), G_CALLBACK(bw_message_select_all_cb)}
+     N_("Select entire mail"), G_CALLBACK(bw_message_select_all_cb)},
+    {"FindInMessage", NULL, N_("_Find in message"), "slash",
+     N_("Find a string in this message"),
+     G_CALLBACK(bw_find_in_message_cb)}
 #endif /* ENABLE_TOUCH_UI */
 };
 
@@ -669,6 +673,7 @@
 "      <separator/>"
 "      <menuitem action='Find'/>"
 "      <menuitem action='FindNext'/>"
+"      <menuitem action='FindInMessage'/>"
 "      <separator/>"
 "      <menuitem action='Filters'/>"
 "      <menuitem action='ExportFilters'/>"
@@ -1510,6 +1515,7 @@
 
     window = g_object_new(BALSA_TYPE_WINDOW, NULL);
     window->vbox = gtk_vbox_new(FALSE, 0);
+    gtk_widget_show(window->vbox);
     gtk_container_add(GTK_CONTAINER(window), window->vbox);
 
     gtk_window_set_title(GTK_WINDOW(window), "Balsa");
@@ -1558,6 +1564,7 @@
                      G_CALLBACK(bw_window_state_event_cb),
                      window->statusbar);
     gtk_box_pack_start(GTK_BOX(hbox), window->statusbar, TRUE, TRUE, 0);
+    gtk_widget_show_all(hbox);
 
 #if 0
     gnome_app_install_appbar_menu_hints(GNOME_APPBAR(balsa_app.appbar),
@@ -1696,7 +1703,7 @@
                      G_CALLBACK(bw_cancel_new_mail_notification), NULL);
 #endif
 
-    gtk_widget_show_all(GTK_WIDGET(window));
+    gtk_widget_show(GTK_WIDGET(window));
     return GTK_WIDGET(window);
 }
 
@@ -4168,6 +4175,14 @@
 }
 
 static void
+bw_find_in_message_cb(GtkAction * action,gpointer data)
+{
+    BalsaWindow *window = data;
+    if (balsa_app.previewpane)
+        balsa_message_find_in_message(BALSA_MESSAGE(window->preview));
+}
+
+static void
 bw_filter_dlg_cb(GtkAction * action, gpointer data)
 {
     filters_edit_dialog();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]