[PATCH (Experimental)] : find/find again for Balsa



	Hi all,
here a patch that provides a find/find again capability to Balsa. Consider 
it as a proof of concept or some sort :)
I mean that this patch may look as an ugly hack (and it is :), it is by no 
mean in final state (in particular it touches a lot of files, and it'd be 
better had a new source file to implement part of the patch).
But it works (at least for me).
You have to apply it AFTER filters-1.2.3-1.patch (bugzilla # 63459) (I 
haven't posted it to bugzilla, it's too experimental for now).
Have fun
Comments welcome, like always. :)
Bye
Manu
diff -uN balsa-1.2.3-new/src/balsa-index.c balsa-1.2.3-dev/src/balsa-index.c
--- balsa-1.2.3-new/src/balsa-index.c	Thu Nov  8 18:11:42 2001
+++ balsa-1.2.3-dev/src/balsa-index.c	Sun Nov 11 13:28:49 2001
@@ -48,6 +48,10 @@
 #include "sendmsg-window.h"
 #include "store-address.h"
 
+#ifdef BALSA_SHOW_ALL
+#include "filter.h"
+#endif /* BALSA_SHOW_ALL */
+
 /* constants */
 #define BUFFER_SIZE 1024
 
@@ -97,7 +101,11 @@
                                          gfloat row_align);
 static GtkCTreeNode *balsa_index_find_node(BalsaIndex * bindex,
                                            gboolean previous,
-                                           LibBalsaMessageFlag flag);
+                                           LibBalsaMessageFlag flag
+#ifdef BALSA_SHOW_ALL
+					   ,gint op,GSList * conditions
+#endif
+					   );
 static void balsa_index_transfer_messages(BalsaIndex * bindex,
                                           LibBalsaMailbox * mailbox);
 static void balsa_index_idle_remove(gpointer data);
@@ -511,7 +519,11 @@
 balsa_index_set_first_new_message(BalsaIndex * bindex)
 {
     GtkCTreeNode *node =
-        balsa_index_find_node(bindex, FALSE, LIBBALSA_MESSAGE_FLAG_NEW);
+        balsa_index_find_node(bindex, FALSE, LIBBALSA_MESSAGE_FLAG_NEW
+#ifdef BALSA_SHOW_ALL
+			      , FILTER_NOOP, NULL
+#endif /* BALSA_SHOW_ALL */
+			      );
     if (node)
         bindex->first_new_message =
             LIBBALSA_MESSAGE(gtk_ctree_node_get_row_data
@@ -528,6 +540,11 @@
     GtkCTreeNode *next;                 /* returns first matching
                                            after selection */
     GtkCTreeNode *last;                 /* returns last matching */
+#ifdef BALSA_SHOW_ALL
+    gint conditions_op;
+    /* This list is not owned by the struct, so it is not its responsability to free it */
+    GSList * conditions;
+#endif /* BALSA_SHOW_ALL */
 };
 
 /* 
@@ -932,12 +949,13 @@
     } else {
         LibBalsaMessage *message =
             LIBBALSA_MESSAGE(gtk_ctree_node_get_row_data(ctree, node));
-        /* if we're not looking for flagged messages, we want only
+        /* if we're not looking for flagged messages or we are called by a search function, we want only
          * viewable messages
          * if we are looking for flagged messages, we want those
          * that match, viewable or not */
-        if ((b->flag == 0 && gtk_ctree_is_viewable(ctree, node))
-            || (b->flag & message->flags)) {
+        if ((b->flag == 0 && !b->conditions && gtk_ctree_is_viewable(ctree, node))
+            || (b->flag & message->flags)
+	    || (b->conditions && match_conditions(b->conditions_op,b->conditions,message))) {
             if (b->first == NULL)
                 /* first matching message */
                 b->first = node;
@@ -978,7 +996,11 @@
  */
 static GtkCTreeNode *
 balsa_index_find_node(BalsaIndex * bindex, gboolean previous,
-                      LibBalsaMessageFlag flag)
+                      LibBalsaMessageFlag flag
+#ifdef BALSA_SHOW_ALL
+		      ,gint op,GSList * conditions
+#endif /* BALSA_SHOW_ALL */
+		      )
 {
     GtkCTreeNode *node;
     struct balsa_index_scan_info *bi;
@@ -990,6 +1012,10 @@
         GTK_CLIST(bindex->ctree)->selection
         ? g_list_last(GTK_CLIST(bindex->ctree)->selection)->data : NULL;
     bi->flag = flag;
+#ifdef BALSA_SHOW_ALL
+    bi->conditions_op=op;
+    bi->conditions=conditions;
+#endif /* BALSA_SHOW_ALL */
     gtk_ctree_pre_recursive(bindex->ctree, NULL, (GtkCTreeFunc)
                             balsa_index_scan_node, bi);
     node = previous ? bi->previous : bi->next;
@@ -1004,31 +1030,59 @@
 void
 balsa_index_select_next(BalsaIndex * bindex)
 {
-    balsa_index_select_node(bindex, balsa_index_find_node(bindex, 
-                            FALSE, 0));
+    balsa_index_select_node(bindex, 
+			    balsa_index_find_node(bindex, 
+						  FALSE, 0
+#ifdef BALSA_SHOW_ALL
+						  , FILTER_NOOP, NULL
+#endif /* BALSA_SHOW_ALL */
+						  ));
 }
 
 void
 balsa_index_select_previous(BalsaIndex * bindex)
 {
-    balsa_index_select_node(bindex, balsa_index_find_node(bindex, 
-                            TRUE, 0));
+    balsa_index_select_node(bindex,
+			    balsa_index_find_node(bindex, 
+						  TRUE, 0
+#ifdef BALSA_SHOW_ALL
+						  , FILTER_NOOP, NULL
+#endif /* BALSA_SHOW_ALL */
+						  ));
 }
 
 void
 balsa_index_select_next_unread(BalsaIndex * bindex)
 {
-    balsa_index_select_node(bindex, balsa_index_find_node(bindex, 
-                            FALSE, LIBBALSA_MESSAGE_FLAG_NEW));
+    balsa_index_select_node(bindex,
+			    balsa_index_find_node(bindex, 
+						  FALSE, LIBBALSA_MESSAGE_FLAG_NEW
+#ifdef BALSA_SHOW_ALL
+						  , FILTER_NOOP, NULL
+#endif /* BALSA_SHOW_ALL */
+						  ));
 }
 
 void
 balsa_index_select_next_flagged(BalsaIndex * bindex)
 {
-    balsa_index_select_node(bindex, balsa_index_find_node(bindex, 
-                            FALSE, LIBBALSA_MESSAGE_FLAG_FLAGGED));
+    balsa_index_select_node(bindex,
+			    balsa_index_find_node(bindex, 
+						  FALSE, LIBBALSA_MESSAGE_FLAG_FLAGGED
+#ifdef BALSA_SHOW_ALL
+						  , FILTER_NOOP, NULL
+#endif /* BALSA_SHOW_ALL */
+						  ));
+}
+
+#ifdef BALSA_SHOW_ALL
+
+void balsa_index_find(BalsaIndex * bindex,gint op,GSList * conditions,gboolean previous)
+{
+    balsa_index_select_node(bindex,balsa_index_find_node(bindex,previous,0,op,conditions));
 }
 
+#endif /* BALSA_SHOW_ALL */
 /* balsa_index_scan_selection:
  * callback for pre-recursive search for next message after moving one
  * or more message out of the mailbox
diff -uN balsa-1.2.3-new/src/balsa-index.h balsa-1.2.3-dev/src/balsa-index.h
--- balsa-1.2.3-new/src/balsa-index.h	Thu Nov  8 18:11:42 2001
+++ balsa-1.2.3-dev/src/balsa-index.h	Sun Nov 11 08:57:05 2001
@@ -101,6 +101,10 @@
     void balsa_index_select_previous(BalsaIndex *);
     void balsa_index_select_row(BalsaIndex * bindex, gint row);
 
+#ifdef BALSA_SHOW_ALL
+    void balsa_index_find(BalsaIndex * bindex,gint op,GSList * conditions,gboolean previous);
+#endif /* BALSA_SHOW_ALL */
+
 /* retrieve the selection */
     void balsa_index_get_selected_rows(BalsaIndex * bindex,
 				       GtkCTreeNode *** rows,
diff -uN balsa-1.2.3-new/src/filter-run-callbacks.c balsa-1.2.3-dev/src/filter-run-callbacks.c
--- balsa-1.2.3-new/src/filter-run-callbacks.c	Thu Nov  8 18:13:05 2001
+++ balsa-1.2.3-dev/src/filter-run-callbacks.c	Sun Nov 11 12:59:05 2001
@@ -145,6 +145,7 @@
     case 0:			/* Apply button */
 	if (!run_filters_on_mailbox(p->selected_filters,p->mbox))
 	    balsa_information(LIBBALSA_INFORMATION_ERROR,_("Error when applying filters"));
+	enable_empty_trash(TRASH_CHECK);
 	return;
     case 1:                     /* OK button */
 	save_filters(p);
diff -uN balsa-1.2.3-new/src/filter-run-dialog.c balsa-1.2.3-dev/src/filter-run-dialog.c
--- balsa-1.2.3-new/src/filter-run-dialog.c	Thu Nov  8 18:13:05 2001
+++ balsa-1.2.3-dev/src/filter-run-dialog.c	Sun Nov 11 12:46:18 2001
@@ -256,7 +256,6 @@
        | \---/  | \---/  |
        \-----------------/
      */
-
     gnome_dialog_append_buttons(GNOME_DIALOG(p),
 				GNOME_STOCK_BUTTON_APPLY,
 				GNOME_STOCK_BUTTON_OK,
diff -uN balsa-1.2.3-new/src/main-window.c balsa-1.2.3-dev/src/main-window.c
--- balsa-1.2.3-new/src/main-window.c	Thu Nov  8 18:13:05 2001
+++ balsa-1.2.3-dev/src/main-window.c	Sun Nov 11 14:03:40 2001
@@ -58,6 +58,11 @@
 #include "threads.h"
 #endif
 
+#ifdef BALSA_SHOW_ALL
+#include "filter.h"
+#include "filter-funcs.h"
+#endif
+
 #include "libinit_balsa/init_balsa.h"
 
 #define MAILBOX_DATA "mailbox_data"
@@ -200,6 +205,9 @@
 static void select_part_cb(BalsaMessage * bm, gpointer data);
 
 #ifdef BALSA_SHOW_ALL
+static void find_real(BalsaIndex * bindex,gboolean again);
+static void find_cb(GtkWidget * widget, gpointer data);
+static void find_again_cb(GtkWidget * widget, gpointer data);
 static void filter_dlg_cb(GtkWidget * widget, gpointer data);
 static void filter_export_cb(GtkWidget * widget, gpointer data);
 #endif
@@ -332,10 +340,11 @@
     GNOMEUIINFO_SEPARATOR,
 #define MENU_FILE_ADDRESS_POS 9
     {
-     GNOME_APP_UI_ITEM, N_("_Address Book..."),
-     N_("Open the address book"),
-     address_book_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
-     GNOME_STOCK_MENU_BOOK_RED, 'B', 0, NULL},
+	GNOME_APP_UI_ITEM, N_("_Address Book..."),
+	N_("Open the address book"),
+	address_book_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
+	GNOME_STOCK_MENU_BOOK_RED, 'B', 0, NULL
+    },
     GNOMEUIINFO_SEPARATOR,
     GNOMEUIINFO_MENU_EXIT_ITEM(balsa_quit_nicely, NULL),
 
@@ -344,21 +353,21 @@
 
 static GnomeUIInfo edit_menu[] = {
     /* FIXME: Features to hook up... */
-    /*  GNOMEUIINFO_MENU_UNDO_ITEM(NULL, NULL); */
-    /*  GNOMEUIINFO_MENU_REDO_ITEM(NULL, NULL); */
+    /*  GNOMEUIINFO_MENU_UNDO_ITEM(NULL, NULL), */
+    /*  GNOMEUIINFO_MENU_REDO_ITEM(NULL, NULL), */
     /*  GNOMEUIINFO_SEPARATOR, */
 #define MENU_EDIT_COPY_POS 0
     GNOMEUIINFO_MENU_COPY_ITEM(copy_cb, NULL),
 #define MENU_EDIT_SELECT_ALL_POS 1
     GNOMEUIINFO_MENU_SELECT_ALL_ITEM(select_all_cb, NULL),
-    /* GNOMEUINFO_SEPARATOR, */
-    /*  GNOMEUIINFO_MENU_FIND_ITEM(NULL, NULL); */
-    /*  GNOMEUIINFO_MENU_FIND_AGAIN_ITEM(NULL, NULL); */
+#ifdef BALSA_SHOW_ALL
+    GNOMEUIINFO_SEPARATOR,
+    GNOMEUIINFO_MENU_FIND_ITEM(find_cb, NULL),
+    GNOMEUIINFO_MENU_FIND_AGAIN_ITEM(find_again_cb, NULL),
     /*  GNOMEUIINFO_MENU_REPLACE_ITEM(NULL, NULL); */
 /*     GNOMEUIINFO_SEPARATOR, */
 /* #define MENU_EDIT_PREFERENCES_POS 3 */
 /*     GNOMEUIINFO_MENU_PREFERENCES_ITEM(open_preferences_manager, NULL), */
-#ifdef BALSA_SHOW_ALL
     GNOMEUIINFO_SEPARATOR,
     GNOMEUIINFO_ITEM_STOCK(N_("_Filters..."), N_("Manage filters"),
                            filter_dlg_cb, GNOME_STOCK_MENU_PROP),
@@ -2539,11 +2548,182 @@
 }
 
 #ifdef BALSA_SHOW_ALL
+
+static void 
+find_real(BalsaIndex * bindex,gboolean again)
+{
+    /* FIXME : later we could do a search based on a complete filter */
+    static filter * f=NULL;
+    /* Condition set up for the search, it will be of type CONDITION_NONE if nothing has been set up */
+    static condition * cnd=NULL;
+    GSList * conditions;
+    static gboolean reverse=FALSE;
+
+    if (!cnd) {
+	cnd=condition_new();
+	if (!cnd) {
+	    balsa_information(LIBBALSA_INFORMATION_ERROR,_("Not enough memory"));
+	    return;
+	}
+	cnd->type=CONDITION_NONE;
+    }
+
+    /* first search, so set up the match rule(s) */
+    if (!again || (!f && cnd->type==CONDITION_NONE)) {
+	GnomeDialog * dia=GNOME_DIALOG(gnome_dialog_new(_("Search a message"),
+							GNOME_STOCK_BUTTON_OK,
+							GNOME_STOCK_BUTTON_CANCEL,
+							NULL));
+	GtkWidget * reverse_button,* search_entry, *w,* page, *table;
+	GtkWidget * matching_fields_body, *matching_fields_from,* matching_fields_to;
+	GtkWidget * matching_fields_cc,* matching_fields_subject;
+	gint ok;
+	
+	gnome_dialog_close_hides(dia,TRUE);
+	/* FIXME : we'll set up this callback later when selecting filters has been enabled
+	   gtk_signal_connect(GTK_OBJECT(dia),"clicked",find_dialog_button_cb,&f);
+	*/
+	reverse_button = gtk_check_button_new_with_label(_("Reverse search"));
+
+	page=gtk_table_new(2, 1, FALSE);
+	w = gtk_label_new(_("Search for:"));
+	gtk_table_attach(GTK_TABLE(page),w,0, 1, 0, 1,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	search_entry = gtk_entry_new_with_max_length(30);
+	gtk_table_attach(GTK_TABLE(page),search_entry,1, 2, 0, 1,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	gtk_box_pack_start(GTK_BOX(dia->vbox), page, FALSE, FALSE, 2);
+
+	/* builds the toggle buttons to specify fields concerned by the search */
+	page = gtk_table_new(3, 7, FALSE);
+    
+	w = gtk_frame_new(_("In:"));
+	gtk_frame_set_label_align(GTK_FRAME(w), GTK_POS_LEFT, GTK_POS_TOP);
+	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
+	gtk_table_attach(GTK_TABLE(page),
+			 w,
+			 0, 3, 0, 2,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 5, 5);
+    
+	table = gtk_table_new(3, 3, TRUE);
+	gtk_container_add(GTK_CONTAINER(w), table);
+		
+	matching_fields_body = gtk_check_button_new_with_label(_("Body"));
+	gtk_table_attach(GTK_TABLE(table),
+			 matching_fields_body,
+			 0, 1, 0, 1,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	matching_fields_to = gtk_check_button_new_with_label(_("To:"));
+	gtk_table_attach(GTK_TABLE(table),
+			 matching_fields_to,
+			 1, 2, 0, 1,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	matching_fields_from = gtk_check_button_new_with_label(_("From:"));
+	gtk_table_attach(GTK_TABLE(table),
+			 matching_fields_from,
+			 1, 2, 1, 2,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	matching_fields_subject = gtk_check_button_new_with_label(_("Subject"));
+	gtk_table_attach(GTK_TABLE(table),
+			 matching_fields_subject,
+			 2, 3, 0, 1,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	matching_fields_cc = gtk_check_button_new_with_label(_("Cc:"));
+	gtk_table_attach(GTK_TABLE(table),
+			 matching_fields_cc,
+			 2, 3, 1, 2,
+			 GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+	gtk_box_pack_start(GTK_BOX(dia->vbox), page, FALSE, FALSE, 2);
+
+	gtk_box_pack_start(GTK_BOX(dia->vbox), gtk_hseparator_new(), FALSE, FALSE, 2);
+	gtk_box_pack_start(GTK_BOX(dia->vbox), reverse_button,TRUE,TRUE,0);
+	gtk_widget_show_all(dia->vbox);
+
+	if (cnd->match.string)
+	    gtk_entry_set_text(GTK_ENTRY(search_entry),cnd->match.string);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reverse_button),reverse);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matching_fields_body),
+				     CONDITION_CHKMATCH(cnd,CONDITION_MATCH_BODY));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matching_fields_to),
+				     CONDITION_CHKMATCH(cnd,CONDITION_MATCH_TO));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matching_fields_from),
+				     CONDITION_CHKMATCH(cnd,CONDITION_MATCH_FROM));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matching_fields_subject),
+				     CONDITION_CHKMATCH(cnd,CONDITION_MATCH_SUBJECT));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matching_fields_cc),
+				     CONDITION_CHKMATCH(cnd,CONDITION_MATCH_CC));
+
+	do {
+	    ok=gnome_dialog_run(dia);
+	    if (ok==0) {
+		reverse=GTK_TOGGLE_BUTTON(reverse_button)->active;
+		g_free(cnd->match.string);
+		cnd->match.string=g_strdup(gtk_entry_get_text(GTK_ENTRY(search_entry)));
+		cnd->match_fields=CONDITION_EMPTY;
+
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matching_fields_body)))
+		    CONDITION_SETMATCH(cnd,CONDITION_MATCH_BODY);
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matching_fields_to)))
+		    CONDITION_SETMATCH(cnd,CONDITION_MATCH_TO);
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matching_fields_subject)))
+		    CONDITION_SETMATCH(cnd,CONDITION_MATCH_SUBJECT);
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matching_fields_from)))
+		    CONDITION_SETMATCH(cnd,CONDITION_MATCH_FROM);
+		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matching_fields_cc)))
+		    CONDITION_SETMATCH(cnd,CONDITION_MATCH_CC);
+		if (cnd->match_fields!=CONDITION_EMPTY && cnd->match.string[0])
+		    /* FIXME : We should print error messages, but for that we should first make find dialog non-modal
+		     * balsa_information(LIBBALSA_INFORMATION_ERROR,_("You must specify at least one field to look in"));
+		     *balsa_information(LIBBALSA_INFORMATION_ERROR,_("You must provide a non-empty string")); */
+		    ok=1;
+		else ok=-1;
+	    }
+	    else ok=-1;
+	}
+	while (ok==0);
+	gtk_widget_destroy(GTK_WIDGET(dia));
+	/* Here ok==1 means OK button was pressed, search is valid so let's go
+	 * else cancel was pressed return */
+	if (ok!=1) return;
+	cnd->type=CONDITION_SIMPLE;
+    }
+
+    if (f) {
+	GSList * lst=g_slist_append(NULL,f);
+	if (!filters_prepare_to_run(lst)) return;
+	g_slist_free(lst);
+	conditions=f->conditions;
+    }
+    else conditions=g_slist_append(NULL,cnd);
+
+    balsa_index_find(bindex,f ? f->conditions_op : FILTER_OP_OR,conditions,reverse);
+
+    /* FIXME : See if this does not lead to a segfault because of balsa_index_scan_info */
+    if (!f) g_slist_free(conditions);
+}
+
+static void
+find_cb(GtkWidget * widget,gpointer data)
+{
+    GtkWidget * bindex;
+    if ((bindex=balsa_window_find_current_index(BALSA_WINDOW(data))))
+	find_real(BALSA_INDEX(bindex),FALSE);
+}
+
+static void
+find_again_cb(GtkWidget * widget,gpointer data)
+{
+    GtkWidget * bindex;
+    if ((bindex=balsa_window_find_current_index(BALSA_WINDOW(data))))
+	find_real(BALSA_INDEX(bindex),TRUE);
+}
+
 static void
 filter_dlg_cb(GtkWidget * widget, gpointer data)
 {
     filters_edit_dialog();
 }
+
 static void
 filter_export_cb(GtkWidget * widget, gpointer data)
 {
Common subdirectories: balsa-1.2.3-new/src/pixmaps and balsa-1.2.3-dev/src/pixmaps


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