[PATCH]



	Hi all,
here is the new version of the smart search patch (against 1.3.7, should 
apply cleanly on 1.4.0, let me know if not). This fixes the problems seen 
by Peter.
Bye
Manu
--- /home/manu/prog/balsa-cvs/balsa/src/balsa-index.c	Sun Jul  7 06:47:54 2002
+++ balsa-current/src/balsa-index.c	Wed Aug 21 14:01:29 2002
@@ -49,6 +49,7 @@
 #include "store-address.h"
 
 #include "filter.h"
+#include "filter-funcs.h"
 
 #define CLIST_WORKAROUND
 #if defined(CLIST_WORKAROUND)
@@ -72,6 +73,9 @@
 			       gpointer data);
 
 /* statics */
+static void bndx_match_struct_destroy(BalsaIndex * index);
+static GHashTable * bndx_get_matching_messages(BalsaIndex * index,gint op,
+					       GSList * cnd);
 static void balsa_index_set_sort_order(BalsaIndex * bindex, int column, 
 				    GtkSortType order);
 static void balsa_index_set_first_new_message(BalsaIndex * bindex);
@@ -257,6 +261,20 @@
     klass->unselect_message = NULL;
 }
 
+/* Free the match struct */
+static void
+bndx_match_struct_destroy(BalsaIndex * index)
+{
+    if (index->match_struct) {
+	if (index->match_struct->conditions)
+	    libbalsa_conditions_free(index->match_struct->conditions);
+	if (index->match_struct->matching_messages)
+	    g_hash_table_destroy(index->match_struct->matching_messages);
+	g_free(index->match_struct);
+	index->match_struct = NULL;
+    }
+}
+
 static void
 balsa_index_init(BalsaIndex * bindex)
 {
@@ -377,6 +395,9 @@
     gtk_signal_connect(GTK_OBJECT(bindex->ctree), "drag-data-get",
                        GTK_SIGNAL_FUNC(balsa_index_drag_cb), NULL);
 
+    /* Initializing the match structure */
+    bindex->match_struct = NULL;
+
     g_get_current_time (&bindex->last_use);
     GTK_OBJECT_UNSET_FLAGS (bindex->ctree, GTK_CAN_FOCUS);
     gtk_widget_show_all (GTK_WIDGET(bindex));
@@ -994,9 +1015,12 @@
         ? g_list_last(GTK_CLIST(bindex->ctree)->selection)->data : NULL;
     bi->flag = flag;
     if(conditions) {
+	/* Remark : this hash table is owned by the index and
+	   will be freed when necessary. We don't need to take care of
+	   thar here.
+	*/
         bi->matching = 
-            libbalsa_mailbox_get_matching(bindex->mailbox_node->mailbox, 
-                                          op, conditions);
+            bndx_get_matching_messages(bindex, op, conditions);
     }
     gtk_ctree_pre_recursive(bindex->ctree, NULL, (GtkCTreeFunc)
                             balsa_index_scan_node, bi);
@@ -1006,7 +1030,7 @@
          * matching */
         node = bi->first;
     g_free(bi);
-    if(bi->matching) g_hash_table_destroy(bi->matching);
+
     return node;
 }
 
@@ -1514,9 +1538,9 @@
     gtk_clist_freeze(GTK_CLIST (bindex->ctree));
     balsa_index_add(bindex, message);
     if(bindex->mailbox_node->mailbox->new_messages==0){
-      balsa_index_threading(bindex);
-      gtk_clist_sort (GTK_CLIST (bindex->ctree));
-      DO_CLIST_WORKAROUND(GTK_CLIST (bindex->ctree));
+	balsa_index_threading(bindex);
+	gtk_clist_sort (GTK_CLIST (bindex->ctree));
+	DO_CLIST_WORKAROUND(GTK_CLIST (bindex->ctree));
     }
     gtk_clist_thaw (GTK_CLIST (bindex->ctree));
     balsa_mblist_update_mailbox(balsa_app.mblist, 
@@ -1634,6 +1658,9 @@
 	bindex->mailbox_node = NULL;
     }
 
+    /* destroy the match struct */
+    bndx_match_struct_destroy(bindex);
+
     if (GTK_OBJECT_CLASS(parent_class)->destroy)
         (*GTK_OBJECT_CLASS(parent_class)->destroy) (obj);
 }
@@ -2535,3 +2562,131 @@
     else if (to_mailbox == balsa_app.trash)
         enable_empty_trash(TRASH_FULL);
 }
+
+/* This func is a wrapper for libbalsa_mailbox_get_matching to be as smart
+   as possible : i.e. we don't want to recalculate the matching messages on
+   a "find again" request (I mean if the mailbox content has not changed in
+   between).
+   Here is the idea to be sure we'll recalculate when necessary : connect
+   to the mailbox signals telling us that it is changing. To be a bit smarter
+   we connect only to the "add" messages, because the remove ones are not
+   interesting for us, we only keep a removed message in our matching list,
+   nothing serious.
+*/
+
+/* Helper to compare regexs */
+
+static gboolean
+compare_regexs(GSList * c1,GSList * c2)
+{
+    GSList * l1, *l2;
+    LibBalsaConditionRegex * r1,* r2;
+
+    for (;c1;c1 = g_slist_next(c1)) {
+	r1 = c1->data;
+	for (l2 = c2;l2 ;l2 = g_slist_next(l2)) {
+	    r2 = l2->data;
+	    if (strcmp(r1->string,r2->string)==0)
+		break;
+	}
+	if (!l2) return FALSE;
+    }
+    return TRUE;
+}
+
+/* Helper to compare conditions, a bit obscure at first glance
+   but we have to compare complex structure, so we must check
+   all fields.
+*/
+static gboolean
+compare_conditions(GSList * cnd1,GSList * cnd2)
+{
+    GSList * l1 = cnd1,* l2 = g_slist_copy(cnd2),* tmp;
+    gboolean OK;
+
+    for (;l1 && l2;l1 = g_slist_next(l1)) {
+	LibBalsaCondition * c1 = l1->data;
+	LibBalsaCondition * c2 = NULL;
+
+	OK = FALSE;
+	for (tmp = l2;tmp && !OK;) {
+	    c2 = tmp->data;
+	    switch (c1->type) {
+	    case CONDITION_SIMPLE:
+		if ((c2->type == CONDITION_SIMPLE) 
+		    && (g_strcasecmp(c1->match.string,c2->match.string) == 0))
+		    OK = TRUE;
+		break;
+	    
+	    case CONDITION_REGEX:
+		if ((c2->type == CONDITION_REGEX) &&
+		    compare_regexs(c1->match.regexs,c2->match.regexs))
+		    OK = TRUE;
+		break;
+	    case CONDITION_DATE:
+		if ((c2->type == CONDITION_DATE) &&
+		    (c1->match.interval.date_low == c2->match.interval.date_low) &&
+		    (c1->match.interval.date_high == c2->match.interval.date_high))
+		    OK = TRUE;
+		break;
+		
+	    case CONDITION_FLAG:
+		if ((c2->type == CONDITION_FLAG) &&
+		    (c1->match.flags == c2->match.flags))
+		    OK = TRUE;
+		break;
+	    }    
+	    tmp = g_slist_next(tmp);
+	}
+	/* We found the current condition of l1, remove it from l2 */
+	if (OK)
+	    l2 = g_slist_remove(l2,c2);
+	/* Else the conditions list differ, stop the process */
+	else break;
+    }
+    /* There is equality only when l1 = l2 = NULL */
+    if (!l2 && !l1)
+	return TRUE;
+    g_slist_free(l2);
+    return FALSE;
+}
+static GHashTable *
+bndx_get_matching_messages(BalsaIndex * index,gint op, GSList * conditions)
+{
+    /* This is illegal, we return NULL and change nothing */
+    if ((op == FILTER_NOOP) || !conditions)
+	return NULL;
+    
+    if (!index->match_struct) {
+	index->match_struct = g_new(BalsaIndexMatch,1);
+	index->match_struct->op = FILTER_NOOP;
+	index->match_struct->conditions = NULL;
+	index->match_struct->matching_messages = NULL;
+    }
+    /* Test if we need to recalculate the matching messages
+       cases where we need it :
+       - the new op and conditions differ from the current ones
+       - index->match->matching_messages == NULL : this means
+       that we never calculated it or that the mailbox content
+	 has changed.
+    */
+    if (!index->match_struct->matching_messages ||
+	(op != index->match_struct->op) ||
+	!compare_conditions(index->match_struct->conditions,conditions)) {
+	GSList * cnd;
+	/* We make a copy of the conditions list, and first drop the preceding ones */
+	libbalsa_conditions_free(index->match_struct->conditions);
+	index->match_struct->conditions = NULL;
+	for (cnd = conditions;cnd;cnd = g_slist_next(cnd))
+	    index->match_struct->conditions =
+		g_slist_prepend(index->match_struct->conditions,
+				libbalsa_condition_clone(cnd->data));
+	index->match_struct->conditions = g_slist_reverse(index->match_struct->conditions);
+	index->match_struct->op = op;
+	if (index->match_struct->matching_messages)
+	    g_hash_table_destroy(index->match_struct->matching_messages);
+	index->match_struct->matching_messages =
+	    libbalsa_mailbox_get_matching(index->mailbox_node->mailbox,op,conditions);
+    }
+    return index->match_struct->matching_messages;
+}
Only in balsa-current/src: balsa-index.c~
diff -u /home/manu/prog/balsa-cvs/balsa/src/balsa-index.h balsa-current/src/balsa-index.h
--- /home/manu/prog/balsa-cvs/balsa/src/balsa-index.h	Sat May 18 08:29:09 2002
+++ balsa-current/src/balsa-index.h	Sat Aug 17 19:12:35 2002
@@ -30,6 +30,25 @@
 extern "C" {
 #endif				/* __cplusplus */
 
+    /* Struct used to keep track of the last sort we've made on an index
+       the idea being to avoid unnecessary recalculation */
+
+    struct _BalsaIndexMatch {
+	/* Fields describing the current matching conditions
+	   Remark : conditions is a copy, it is the responsibility
+	   of the owner (here the index) to free it
+	 */
+	gint op;
+	GSList * conditions;
+
+	/* This is the list of matching messages corresponding to the current
+	   conditions.
+	   Remark : we drop this list each time the mailbox content has changed
+	   or the conditions or the op has changed
+	*/
+	GHashTable * matching_messages;
+    };
+
     GtkType balsa_index_get_type(void);
 
 #define BALSA_TYPE_INDEX          (balsa_index_get_type ())
@@ -41,6 +60,7 @@
 
     typedef struct _BalsaIndex BalsaIndex;
     typedef struct _BalsaIndexClass BalsaIndexClass;
+    typedef struct _BalsaIndexMatch BalsaIndexMatch;
 
     struct _BalsaIndex {
         GtkScrolledWindow sw;    
@@ -56,6 +76,8 @@
 
 	gchar *date_string;
 	gboolean line_length;
+
+	BalsaIndexMatch * match_struct;
     };
 
     struct _BalsaIndexClass {


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