]> granicus.if.org Git - mutt/commitdiff
[patch-0.94.4.vikas.collapse.2] Vikas' collapse-thread
authorThomas Roessler <roessler@does-not-exist.org>
Thu, 27 Aug 1998 23:45:40 +0000 (23:45 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Thu, 27 Aug 1998 23:45:40 +0000 (23:45 +0000)
patch.

12 files changed:
OPS
curs_main.c
functions.h
hdrline.c
init.h
mbox.c
mutt.h
mx.c
pattern.c
protos.h
sort.c
thread.c

diff --git a/OPS b/OPS
index 39282f6ded8364390612f3655a0c8dc52c6f367c..6979d6150cb36f8c7d64d80258337e495eac55ad 100644 (file)
--- a/OPS
+++ b/OPS
@@ -144,3 +144,5 @@ OP_VERSION "show the Mutt version number and date"
 OP_VIEW_ATTACH "view attachment using mailcap entry if necessary"
 OP_VIEW_ATTACHMENTS "show MIME attachments"
 OP_MAIN_SHOW_LIMIT "show currently active limit pattern"
+OP_MAIN_COLLAPSE_THREAD "collapse/uncollapse current thread"
+OP_MAIN_COLLAPSE_ALL "collapse/uncollapse all threads"
index 401a18b711cfecf022b655807a2d0c28e5a28c1d..ef87bcf6855f24b6237409ce5be7946ec3213f3d 100644 (file)
@@ -69,6 +69,7 @@
 
 #define CURHDR Context->hdrs[Context->v2r[menu->current]]
 #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
+#define UNREAD(h) mutt_thread_contains_unread (Context, h)
 
 extern const char *ReleaseDate;
 
@@ -124,7 +125,7 @@ void index_make_entry (char *s, size_t l, MUTTMENU *menu, int num)
     }
   }
 
-  _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag);
+  _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag | M_FORMAT_INDEX);
 }
 
 int index_color (int index_no)
@@ -267,13 +268,14 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
 
     if (Context && !attach_msg)
     {
+      int check;
       /* check for new mail in the mailbox.  If nonzero, then something has
        * changed about the file (either we got new mail or the file was
        * modified underneath us.)
        */
       index_hint = (Context->vcount) ? CURHDR->index : 0;
 
-      if ((i = mx_check_mailbox (Context, &index_hint)) < 0)
+      if ((check = mx_check_mailbox (Context, &index_hint)) < 0)
       {
        if (!Context->path)
        {
@@ -284,8 +286,10 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
 
        set_option (OPTSEARCHINVALID);
       }
-      else if (i == M_NEW_MAIL ||  i == M_REOPENED)
+      else if (check == M_NEW_MAIL || check == M_REOPENED)
       {
+       int *save_new;
+
        /* take note of the current message */
        if (oldcount)
        {
@@ -300,32 +304,75 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
         * they will be visible in the limited view */
         if (Context->pattern)
        {
-          #define this_body Context->hdrs[i]->content
-         if (oldcount)
-          for (i = oldcount; i < Context->msgcount; i++)
+#define THIS_BODY Context->hdrs[j]->content
+         if (oldcount || check == M_REOPENED)
+           for (j = (check == M_REOPENED) ? 0 : oldcount; j < Context->msgcount; j++)
          {
             if (mutt_pattern_exec (Context->limit_pattern,
                                   M_MATCH_FULL_ADDRESS, 
-                                  Context, Context->hdrs[i]))
+                                   Context, Context->hdrs[j]))
             {
-            Context->hdrs[i]->virtual = Context->vcount;
-            Context->v2r[Context->vcount] = i;
-            Context->vcount++;
-            Context->vsize+=this_body->length + this_body->offset -
-                             this_body->hdr_offset;
+               Context->hdrs[j]->virtual = Context->vcount;
+               Context->v2r[Context->vcount] = j;
+               Context->hdrs[j]->limited = 1;
+               Context->vcount++;
+               Context->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
             }
          }
-          #undef this_body
+#undef THIS_BODY
+        }
+
+       /* save the list of new messages */
+       if (oldcount && check != M_REOPENED)
+       {
+         save_new = (int *) safe_malloc (sizeof (int) * (Context->msgcount - oldcount));
+         for (j = oldcount; j < Context->msgcount; j++)
+           save_new[j-oldcount] = Context->hdrs[j]->index;
         }
 
        /* if the mailbox was reopened, need to rethread from scratch */
-       mutt_sort_headers (Context, (i == M_REOPENED));
+       set_option (OPTSORTCOLLAPSE);
+       mutt_sort_headers (Context, (check == M_REOPENED));
+       unset_option (OPTSORTCOLLAPSE);
+
+       /* uncollapse threads with new mail */
+       if ((Sort & SORT_MASK) == SORT_THREADS)
+       {
+         if (check == M_REOPENED)
+         {
+           HEADER *h;
+
+           h = Context->tree;
+           Context->collapsed = 0;
+
+           while (h)
+           {
+             mutt_uncollapse_thread (Context, h);
+             h = h->next;
+           }
+           mutt_set_virtual (Context);
+         }
+         else if (oldcount)
+         {
+           for (j = 0; j < Context->msgcount - oldcount; j++)
+           {
+             int k;
+             
+             for (k = 0; k < Context->msgcount; k++)
+             {
+               HEADER *h = Context->hdrs[k];
+               if (h->index == save_new[j] && (!Context->pattern || h->limited))
+                 mutt_uncollapse_thread (Context, h);
+             }
+           }
+           FREE (&save_new);
+           mutt_set_virtual (Context);
+         }
+       }
 
        menu->current = -1;
        if (oldcount)
        {
-         int j;
-
          /* restore the current message to the message it was pointing to */
          for (j = 0; j < Context->vcount; j++)
            if (Context->hdrs[Context->v2r[j]]->index == menu->oldcurrent)
@@ -339,7 +386,7 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
          menu->current = ci_first_message ();
 
        /* notify the user of new mail */
-       if (i == M_REOPENED)
+       if (check == M_REOPENED)
          mutt_error ("Mailbox was externally modified.  Flags may be wrong.");
        else
        {
@@ -882,7 +929,14 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
          toggle_option (OPTWEED);
 
        unset_option (OPTNEEDRESORT);
-
+       if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
+       {
+         mutt_uncollapse_thread (Context, CURHDR);
+         mutt_set_virtual (Context);
+         if (option (OPTUNCOLLAPSEJUMPNEW))
+           menu->current = mutt_thread_next_new (Context, CURHDR);
+       }
        if ((op = mutt_display_message (CURHDR, attach_msg_status)) == -1)
        {
          unset_option (OPTNEEDRESORT);
@@ -1045,6 +1099,7 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
        menu->current = -1;
        for (j = 0; j != Context->vcount; j++)
        {
+#define CUR Context->hdrs[Context->v2r[i]]
          if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD)
          {
            i++;
@@ -1064,22 +1119,25 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
            }
          }
 
-         if (! Context->hdrs[Context->v2r[i]]->deleted &&
-             ! Context->hdrs[Context->v2r[i]]->read)
+         if ((!CUR->deleted && !CUR->read) ||
+             (CUR->collapsed && !CUR->deleted && UNREAD (CUR)))
          {
            if (op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
-               ! Context->hdrs[Context->v2r[i]]->old)
+               !CUR->old)
            {
              menu->current = i;
              break;
            }
          }
        }
+#undef CUR
        if (menu->current == -1)
        {
+         char *tmp = "";
          menu->current = menu->oldcurrent;
-         mutt_error ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? 
-                     "No new messages." : "No unread messages.");
+         if (Context->pattern)
+           tmp = " in this limited view";
+         mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? "No new messages" : "No unread messages", NONULL (tmp));
        }
        else if (menu->menu == MENU_PAGER)
        {
@@ -1227,6 +1285,81 @@ int mutt_index_menu (int attach_msg /* invoked while attaching a message */)
        }
        break;
 
+      case OP_MAIN_COLLAPSE_THREAD:
+       CHECK_MSGCOUNT;
+       
+       if (CURHDR->collapsed)
+       {
+         menu->current = mutt_uncollapse_thread (Context, CURHDR);
+         mutt_set_virtual (Context);
+         if (option (OPTUNCOLLAPSEJUMPNEW))
+           menu->current = mutt_thread_next_new (Context, CURHDR);
+       }
+       else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR))
+       {
+         menu->current = mutt_collapse_thread (Context, CURHDR);
+         mutt_set_virtual (Context);
+       }
+       else
+       {
+         mutt_error ("Thread contains unread messages.");
+         break;
+       }
+
+       menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+
+       break;
+
+      case OP_MAIN_COLLAPSE_ALL:
+       CHECK_MSGCOUNT;
+
+       if ((Sort & SORT_MASK) != SORT_THREADS)
+       {
+         mutt_error ("Threading is not enabled.");
+         break;
+       }
+
+       {
+        HEADER *h, *base;
+        int final;
+
+        if (CURHDR->collapsed)
+          final = mutt_uncollapse_thread (Context, CURHDR);
+        else if (option (OPTCOLLAPSENEW) || !UNREAD (CURHDR))
+          final = mutt_collapse_thread (Context, CURHDR);
+        else
+          final = CURHDR->virtual;
+
+        base = Context->hdrs[Context->v2r[final]];
+       
+        h = Context->tree;
+        Context->collapsed = !Context->collapsed;
+        while (h)
+        {
+          if (h->collapsed != Context->collapsed)
+          {
+            if (h->collapsed)
+              mutt_uncollapse_thread (Context, h);
+            else if (option (OPTCOLLAPSENEW) || !UNREAD (h))
+              mutt_collapse_thread (Context, h);
+          }
+          h = h->next;
+        }
+
+        mutt_set_virtual (Context);
+        for (j = 0; j < Context->vcount; j++)
+        {
+          if (Context->hdrs[Context->v2r[j]]->index == base->index)
+          {
+            menu->current = j;
+            break;
+          }
+        }
+
+        menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+        break;
+       }
+
        /* --------------------------------------------------------------------
         * These functions are invoked directly from the internal-pager
         */
index 7877f3e20c9276b4570571b6c96f0d8f036bcc41..9579ec7ca81195ed9e32081280e9a66402648ad4 100644 (file)
@@ -68,6 +68,8 @@ struct binding_t OpMain[] = {
   { "bounce-message",          OP_BOUNCE_MESSAGE,              "b" },
   { "change-folder",           OP_MAIN_CHANGE_FOLDER,          "c" },
   { "change-folder-readonly",  OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
+  { "collapse-thread",         OP_MAIN_COLLAPSE_THREAD,        "\033v" },
+  { "collapse-all",            OP_MAIN_COLLAPSE_ALL,           "\033V" },
   { "copy-message",            OP_COPY_MESSAGE,                "C" },
   { "decode-copy",             OP_DECODE_COPY,                 "\033C" },
   { "decode-save",             OP_DECODE_SAVE,                 "\033s" },
index 2e9710b90f376d5186049c31ce8918f82c99a05e..c5b5fd6a7b7d70fde40bb9f284df339a590f9f78 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
@@ -18,7 +18,7 @@
 
 #include "mutt.h"
 #include "mutt_curses.h"
-
+#include "sort.h"
 
 
 #ifdef _PGPPATH
@@ -224,6 +224,9 @@ hdr_format_str (char *dest,
   char fmt[SHORT_STRING], buf2[SHORT_STRING], ch, *p;
   int do_locales, i;
   int optional = (flags & M_FORMAT_OPTIONAL);
+  int threads = ((Sort & SORT_MASK) == SORT_THREADS);
+  int is_index = (flags & M_FORMAT_INDEX);
+#define NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr))
   size_t len;
 
   hdr = hfi->hdr;
@@ -446,22 +449,22 @@ hdr_format_str (char *dest,
       break;
 
     case 's':
-      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-      if (flags & M_FORMAT_TREE)
+      
+      snprintf (fmt, sizeof (fmt), "%s%%%ss", threads && is_index ? "   " : "", prefix);
+      if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
+       snprintf (dest, destlen, "%2d %s", hdr->num_hidden, NONULL(hdr->env->subject));
+      else if (flags & M_FORMAT_TREE)
       {
        if (flags & M_FORMAT_FORCESUBJ)
        {
-         snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree,
-                   hdr->env->subject ? hdr->env->subject : "");
+         snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, NONULL (hdr->env->subject));
          snprintf (dest, destlen, fmt, buf2);
        }
        else
          snprintf (dest, destlen, fmt, hdr->tree);
       }
       else
-      {
-       snprintf (dest, destlen, fmt, hdr->env->subject ? hdr->env->subject : "");
-      }
+       snprintf (dest, destlen, fmt, NONULL (hdr->env->subject));
       break;
 
     case 'S':
@@ -544,7 +547,7 @@ hdr_format_str (char *dest,
       snprintf (buf2, sizeof (buf2),
                "%c%c%c",
                (hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
-               ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N'),
+               ? (NEW ? 'n' : (hdr->replied ? 'r' : ' ')) : (hdr->old ? 'O' : (NEW ? 'n' : 'N')),
                hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
                hdr->tagged ? '*' :
                (hdr->flagged ? '!' :
@@ -563,6 +566,7 @@ hdr_format_str (char *dest,
     mutt_FormatString (dest, destlen, elsestring, hdr_format_str, (unsigned long) hfi, flags);
 
   return (src);
+#undef NEW
 }
 
 void
diff --git a/init.h b/init.h
index 397a8237a98ff8d6202857c34c07e8111cbdff2e..0ffadfe6053418c94140fcf689f38bf785e7177d 100644 (file)
--- a/init.h
+++ b/init.h
@@ -87,6 +87,9 @@ struct option_t MuttVars[] = {
   { "beep_new",                DT_BOOL, R_NONE, OPTBEEPNEW, 0 },
   { "charset",         DT_STR,  R_NONE, UL &Charset, UL "iso-8859-1" },
   { "check_new",       DT_BOOL, R_NONE, OPTCHECKNEW, 1 },
+  { "collapse_new",    DT_BOOL, R_NONE, OPTCOLLAPSENEW, 1 },
+  { "uncollapse_jump_new", DT_BOOL, R_NONE, OPTUNCOLLAPSEJUMPNEW, 0 },
+  { "auto_collapse",   DT_BOOL, R_NONE, OPTAUTOCOLLAPSE, 0 },
   { "confirmappend",   DT_BOOL, R_NONE, OPTCONFIRMAPPEND, 1 },
   { "confirmcreate",   DT_BOOL, R_NONE, OPTCONFIRMCREATE, 1 },
   { "copy",            DT_QUAD, R_NONE, OPT_COPY, M_YES },
diff --git a/mbox.c b/mbox.c
index edae95fd198b4f9498f29a1c789926c209da1b58..d5ef5f566fefc4dfa2d95fc15d97294a9932c623 100644 (file)
--- a/mbox.c
+++ b/mbox.c
@@ -649,7 +649,9 @@ int mbox_sync_mailbox (CONTEXT *ctx)
   {
     save_sort = Sort;
     Sort = SORT_ORDER;
+    set_option (OPTSORTCOLLAPSE);
     mutt_sort_headers (ctx, 0);
+    unset_option (OPTSORTCOLLAPSE);
   }
 
   /* need to open the file for writing in such a way that it does not truncate
@@ -890,7 +892,9 @@ bail:  /* Come here in case of disaster */
     Sort = save_sort;
     /* if the mailbox was reopened, the thread tree will be invalid so make
      * sure to start threading from scratch.  */
+    set_option (OPTSORTCOLLAPSE);
     mutt_sort_headers (ctx, (need_sort == M_REOPENED));
+    unset_option (OPTSORTCOLLAPSE);
   }
 
   return (-1);
diff --git a/mutt.h b/mutt.h
index d68f60ad072a99e023a4630c7480aa7868388636..96160306098123af120240c33d23e23f926b67f0 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -100,7 +100,8 @@ typedef enum
   M_FORMAT_MAKEPRINT   = (1<<2), /* make sure that all chars are printable */
   M_FORMAT_OPTIONAL    = (1<<3),
   M_FORMAT_STAT_FILE   = (1<<4), /* used by mutt_attach_fmt */
-  M_FORMAT_ARROWCURSOR = (1<<5)  /* reserve space for arrow_cursor */
+  M_FORMAT_ARROWCURSOR = (1<<5), /* reserve space for arrow_cursor */
+  M_FORMAT_INDEX       = (1<<6)  /* this is a main index entry */
 } format_flag;
 
 /* types for mutt_add_hook() */
@@ -123,6 +124,12 @@ typedef enum
 #define M_TREE_HIDDEN          9
 #define M_TREE_MAX             10
 
+#define M_THREAD_COLLAPSE      (1<<0)
+#define M_THREAD_UNCOLLAPSE    (1<<1)
+#define M_THREAD_GET_HIDDEN    (1<<2)
+#define M_THREAD_UNREAD                (1<<3)
+#define M_THREAD_NEXT_NEW      (1<<4)
+
 enum
 {
   /* modes for mutt_view_attachment() */
@@ -236,11 +243,13 @@ enum
   OPTASKBCC,
   OPTASKCC,
   OPTATTACHSPLIT,
+  OPTAUTOCOLLAPSE,
   OPTAUTOEDIT,
   OPTAUTOTAG,
   OPTBEEP,
   OPTBEEPNEW,
   OPTCHECKNEW,
+  OPTCOLLAPSENEW,
   OPTCONFIRMAPPEND,
   OPTCONFIRMCREATE,
   OPTEDITHDRS,
@@ -280,6 +289,7 @@ enum
   OPTSUSPEND,
   OPTTHOROUGHSRC,
   OPTTILDE,
+  OPTUNCOLLAPSEJUMPNEW,
   OPTUSE8BITMIME,
   OPTUSEDOMAIN,
   OPTUSEFROM,
@@ -288,7 +298,7 @@ enum
   OPTWRAP,
   OPTWRAPSEARCH,
   OPTWRITEBCC,         /* write out a bcc header? */
-  
+
   /* PGP options */
   
 #ifdef _PGPPATH
@@ -318,6 +328,7 @@ enum
   OPTFORCEREDRAWPAGER, /* (pseudo) used to force a redraw in the pager */
   OPTSORTSUBTHREADS,   /* (pseudo) used when $sort_aux changes */
   OPTNEEDRESCORE,      /* (pseudo) set when the `score' command is used */
+  OPTSORTCOLLAPSE,     /* (pseudo) used by mutt_sort_headers() */
 
 #ifdef _PGPPATH
   OPTPGPCHECKTRUST,    /* (pseudo) used by pgp_select_key () */
@@ -502,6 +513,11 @@ typedef struct header
   unsigned int searched : 1;
   unsigned int matched : 1;
 
+  /* the following are used to support collapsing threads  */
+  unsigned int collapsed : 1; /* is this message part of a collapsed thread? */
+  unsigned int limited : 1;   /* is this message in a limited view?  */
+  size_t num_hidden;          /* number of hidden messages in this view */
+
   int pair; /* color-pair to use when displaying in the index */
 
   time_t date_sent;     /* time when the message was sent (UTC) */
@@ -583,6 +599,7 @@ typedef struct
   unsigned int setgid : 1;
   unsigned int quiet : 1;      /* inhibit status messages? */
   unsigned int revsort : 1;    /* mailbox sorted in reverse? */
+  unsigned int collapsed : 1;   /* are all threads collapsed? */
 } CONTEXT;
 
 typedef struct attachptr
diff --git a/mx.c b/mx.c
index ce611617ed3e9ad8c1a73d7a92d1de9fd215a797..3e05a4f1d77615ead109e79970d3174ed4b687d2 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -540,6 +540,7 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
   ctx->path = safe_strdup (path);
 
   ctx->msgnotreadyet = -1;
+  ctx->collapsed = 0;
   
   if (flags & M_QUIET)
     ctx->quiet = 1;
@@ -956,7 +957,9 @@ int mx_sync_mailbox (CONTEXT *ctx)
 #undef this_body
     ctx->msgcount = j;
 
+    set_option (OPTSORTCOLLAPSE);
     mutt_sort_headers (ctx, 1); /* rethread from scratch */
+    unset_option (OPTSORTCOLLAPSE);
   }
 
   return (rc);
index 2b6d857c86fd613fa82ee62cfb9daf8991bf1d53..53b85d4701b39d355539ee62806eed5a387886e2 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -899,12 +899,18 @@ int mutt_pattern_func (int op, char *prompt)
   if (op == M_LIMIT)
   {
     for (i = 0; i < Context->msgcount; i++)
+    {
       Context->hdrs[i]->virtual = -1;
+      Context->hdrs[i]->limited = 0;
+      Context->hdrs[i]->collapsed = 0;
+      Context->hdrs[i]->num_hidden = 0;
+    }
     Context->vcount = 0;
     Context->vsize = 0;
+    Context->collapsed = 0;
   }
 
-#define this_body Context->hdrs[i]->content
+#define THIS_BODY Context->hdrs[i]->content
 
   for (i = 0; i < Context->msgcount; i++)
     if (mutt_pattern_exec (pat, M_MATCH_FULL_ADDRESS, Context, Context->hdrs[i]))
@@ -925,19 +931,21 @@ int mutt_pattern_func (int op, char *prompt)
          break;
        case M_LIMIT:
          Context->hdrs[i]->virtual = Context->vcount;
+         Context->hdrs[i]->limited = 1;
          Context->v2r[Context->vcount] = i;
          Context->vcount++;
-         Context->vsize+=this_body->length + this_body->offset -
-                         this_body->hdr_offset;
+         Context->vsize+=THIS_BODY->length + THIS_BODY->offset -
+                         THIS_BODY->hdr_offset;
          break;
       }
     }
-#undef this_body
+#undef THIS_BODY
 
   mutt_clear_error ();
 
   if (op == M_LIMIT)
   {
+    Context->collapsed = 0;
     safe_free ((void **) &Context->pattern);
     if (Context->limit_pattern) 
       mutt_pattern_free (&Context->limit_pattern);
@@ -948,6 +956,9 @@ int mutt_pattern_func (int op, char *prompt)
       for (i = 0; i < Context->msgcount; i++)
       {
        Context->hdrs[i]->virtual = i;
+       Context->hdrs[i]->limited = 0;
+       Context->hdrs[i]->num_hidden = 0;
+       Context->hdrs[i]->collapsed = 0;
        Context->v2r[i] = i;
       }
 
index 9a9ed0b6103181df18d24d695854c221cec1af51..43b45508edc95f9bb8fa1a358e53f8302460c51b 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -46,6 +46,13 @@ int _mutt_system (const char *, int);
 #define mutt_previous_subthread(x) _mutt_aside_thread(x,0,1)
 int _mutt_aside_thread (HEADER *, short, short);
 
+#define mutt_collapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_COLLAPSE)
+#define mutt_uncollapse_thread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNCOLLAPSE)
+#define mutt_get_hidden(x,y)_mutt_traverse_thread (x,y,M_THREAD_GET_HIDDEN) 
+#define mutt_thread_contains_unread(x,y) _mutt_traverse_thread (x,y,M_THREAD_UNREAD)
+#define mutt_thread_next_new(x,y) _mutt_traverse_thread(x,y,M_THREAD_NEXT_NEW)
+int _mutt_traverse_thread (CONTEXT *ctx, HEADER *hdr, int flag);
+
 #define ISSPACE(c) isspace((unsigned char)c)
 
 #define mutt_new_parameter() safe_calloc (1, sizeof (PARAMETER))
@@ -123,7 +130,7 @@ void mutt_block_signals_system (void);
 void mutt_body_handler (BODY *, STATE *);
 void mutt_bounce_message (HEADER *, ADDRESS *);
 void mutt_buffy (char *);
-void mutt_check_rescore (CONTEXT *ctx);
+void mutt_check_rescore (CONTEXT *);
 void mutt_clear_error (void);
 void mutt_create_alias (ENVELOPE *, ADDRESS *);
 void mutt_decode_attachment (BODY *, STATE *);
@@ -185,6 +192,7 @@ void mutt_update_encoding (BODY *a);
 void mutt_update_tree (ATTACHPTR **, short);
 void mutt_version (void);
 void mutt_view_attachments (HEADER *);
+void mutt_set_virtual (CONTEXT *);
 
 int mutt_addr_is_user (ADDRESS *);
 int mutt_alias_complete (char *, size_t);
diff --git a/sort.c b/sort.c
index 3ece2f7f121b1dbcc9242acf521d74af23e98fcd..292435e551a08c6734c23093f68541e44c692e57 100644 (file)
--- a/sort.c
+++ b/sort.c
@@ -176,6 +176,7 @@ void mutt_sort_headers (CONTEXT *ctx, int init)
 {
   int i;
   sort_t *sortfunc;
+  int collapse = (option (OPTSORTCOLLAPSE)) ? 0 : 1;
   
   unset_option (OPTNEEDRESORT);
 
@@ -236,15 +237,21 @@ void mutt_sort_headers (CONTEXT *ctx, int init)
 
   /* adjust the virtual message numbers */
   ctx->vcount = 0;
+  if (collapse)
+    ctx->collapsed = 0;
   for (i = 0; i < ctx->msgcount; i++)
   {
-    if (ctx->hdrs[i]->virtual != -1)
+    HEADER *cur = ctx->hdrs[i];
+    if (cur->virtual != -1 || (collapse && cur->collapsed && (!ctx->pattern || cur->limited)))
     {
-      ctx->hdrs[i]->virtual = ctx->vcount;
+      cur->virtual = ctx->vcount;
       ctx->v2r[ctx->vcount] = i;
       ctx->vcount++;
     }
-    ctx->hdrs[i]->msgno = i;
+    cur->msgno = i;
+    cur->num_hidden = mutt_get_hidden (ctx, cur);
+    if (collapse)
+      cur->collapsed = 0;
   }
 
   mutt_cache_index_colors(ctx);
index 8336e91d8f672b5c04b33d21f1bf1aa18205c965..12d85b990cfa8c85c411b485a502df1c1ed344a2 100644 (file)
--- a/thread.c
+++ b/thread.c
  */ 
 
 #include "mutt.h"
+#include "mutt_curses.h"
+#include "mutt_menu.h"
 #include "sort.h"
+#include "mailbox.h"
+#include "copy.h"
+#include "mx.h"
+#include <sys/stat.h>
+#include <utime.h>
+
+#ifdef BUFFY_SIZE
+#include "buffy.h"
+#endif
 
 #include <string.h>
 #include <ctype.h>
@@ -38,7 +49,7 @@ static HEADER *find_reference (HEADER *cur, CONTEXT *ctx)
 }
 
 /* Determines whether to display a message's subject. */
-static int need_display_subject (HEADER *tree)
+static int need_display_subject (CONTEXT *ctx, HEADER *tree)
 {
   HEADER *tmp;
 
@@ -46,7 +57,7 @@ static int need_display_subject (HEADER *tree)
     return (1);
   for (tmp = tree->prev; tmp; tmp = tmp->prev)
   {
-    if (tmp->virtual >= 0)
+    if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited)))
     {
       if (!tmp->subject_changed)
        return (0);
@@ -56,7 +67,7 @@ static int need_display_subject (HEADER *tree)
   }
   for (tmp = tree->parent; tmp; tmp = tmp->parent)
   {
-    if (tmp->virtual >= 0)
+    if (tmp->virtual >= 0 || (tmp->collapsed && (!ctx->pattern || tmp->limited)))
       return (0);
     else if (tmp->subject_changed)
       return (1);
@@ -66,7 +77,7 @@ static int need_display_subject (HEADER *tree)
 
 /* determines whether a later sibling or the child of a later 
    sibling is displayed.  */
-int is_next_displayed (HEADER *tree)
+static int is_next_displayed (CONTEXT *ctx, HEADER *tree)
 {
   int depth = 0;
 
@@ -75,7 +86,7 @@ int is_next_displayed (HEADER *tree)
 
   FOREVER
   {
-    if (tree->virtual >= 0)
+    if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
       return (1);
 
     if (tree->child)
@@ -122,8 +133,8 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize)
 
   FOREVER
   {
-    if (tree->virtual >= 0)
-      tree->display_subject = need_display_subject (tree);
+    if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
+      tree->display_subject = need_display_subject (ctx, tree);
 
     if (depth >= max_depth)
       safe_realloc ((void **) &pfx,
@@ -136,26 +147,26 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize)
     safe_free ((void **) &tree->tree);
     if (!depth)
     {
-      if (tree->virtual >= 0)
+      if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
        tree->tree = safe_strdup ("");
     }
     else
     {
       myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * 2;
-      nextdisp = is_next_displayed (tree);
+      nextdisp = is_next_displayed (ctx, tree);
       
       if (depth && start_depth == depth)
        myarrow[0] = nextdisp ? M_TREE_LTEE : corner;
       else
        myarrow[0] = M_TREE_HIDDEN;
       myarrow[1] = tree->fake_thread ? M_TREE_STAR : M_TREE_HLINE;
-      if (tree->virtual >= 0)
+      if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
       {
        myarrow[2] = M_TREE_RARROW;
        myarrow[3] = 0;
       }
 
-      if (tree->virtual >= 0)
+      if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
       {
        tree->tree = safe_malloc ((2 + depth * 2) * sizeof (char));
        if (start_depth > 1)
@@ -184,7 +195,7 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize)
        mypfx[1] = M_TREE_SPACE;
       }
       depth++;
-      if (tree->virtual >= 0)
+      if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
         start_depth = depth;
       tree = tree->child;
     }
@@ -192,14 +203,14 @@ void mutt_linearize_tree (CONTEXT *ctx, int linearize)
     {
       while (!tree->next && tree->parent)
       {
-       if (tree->virtual >= 0)
+       if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
          start_depth = depth;
        tree = tree->parent;
        if (start_depth == depth)
          start_depth--;
        depth--;
       }
-      if (tree->virtual >= 0)
+      if (tree->virtual >= 0 || (tree->collapsed && (!ctx->pattern || tree->limited)))
        start_depth = depth;
       if ((tree = tree->next) == NULL)
        break;
@@ -671,3 +682,166 @@ int _mutt_aside_thread (HEADER *hdr, short dir, short subthreads)
 
   return (tmp->virtual);
 }
+
+void mutt_set_virtual (CONTEXT *ctx)
+{
+  int i;
+
+  ctx->vcount = 0;
+  ctx->vsize = 0;
+
+#define THIS_BODY cur->content
+  for (i = 0; i < ctx->msgcount; i++)
+  {
+    HEADER *cur = ctx->hdrs[i];
+    if (cur->virtual != -1)
+    {
+      cur->virtual = ctx->vcount;
+      ctx->v2r[ctx->vcount] = i;
+      ctx->vcount++;
+      ctx->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
+      cur->num_hidden = mutt_get_hidden (ctx, cur);
+    }
+  }
+#undef THIS_BODY
+}
+
+int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag)
+{
+  HEADER *roothdr = NULL, *top;
+  int final, reverse = (Sort & SORT_REVERSE), minmsgno;
+  int num_hidden = 0, unread = 0;
+  int min_unread_msgno = INT_MAX, min_unread = cur->virtual;
+#define CHECK_LIMIT (!ctx->pattern || cur->limited)
+
+  if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & M_THREAD_GET_HIDDEN))
+  {
+    mutt_error ("Threading is not enabled.");
+    return (cur->virtual);
+  }
+
+  final = cur->virtual;
+  while (cur->parent) 
+     cur = cur->parent;
+  top = cur;
+  minmsgno = cur->msgno;
+  
+
+  if (!cur->read && CHECK_LIMIT)
+  {
+    unread = 1;
+    if (cur->msgno < min_unread_msgno)
+    {
+      min_unread = cur->virtual;
+      min_unread_msgno = cur->msgno;
+    }
+  }
+
+  if (cur->virtual == -1 && CHECK_LIMIT)
+    num_hidden++;
+
+  if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+  {
+    cur->collapsed = flag & M_THREAD_COLLAPSE;
+    if (cur->virtual != -1)
+    {
+      roothdr = cur;
+      if (flag & M_THREAD_COLLAPSE)
+       final = roothdr->virtual;
+    }
+  }
+
+  if ((cur = cur->child) == NULL)
+  {
+    /* return value depends on action requested */
+    if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+      return (final);
+    else if (flag & M_THREAD_UNREAD)
+      return (unread);
+    else if (flag & M_THREAD_GET_HIDDEN)
+      return (num_hidden);
+    else if (flag & M_THREAD_NEXT_NEW)
+      return (min_unread);
+  }
+  
+  FOREVER
+  {
+    if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+    {
+      cur->collapsed = flag & M_THREAD_COLLAPSE;
+      if (!roothdr && CHECK_LIMIT)
+      {
+       roothdr = cur;
+       if (flag & M_THREAD_COLLAPSE)
+         final = roothdr->virtual;
+      }
+
+      if (reverse && (flag & M_THREAD_COLLAPSE) && (cur->msgno < minmsgno) 
+         && CHECK_LIMIT)
+      {
+       minmsgno = cur->msgno;
+       final = cur->virtual;
+      }
+
+      if (flag & M_THREAD_COLLAPSE)
+      {
+       if (cur != roothdr)
+         cur->virtual = -1;
+      }
+      else 
+      {
+       if (CHECK_LIMIT)
+         cur->virtual = cur->msgno;
+      }
+    }
+
+
+    if (!cur->read && CHECK_LIMIT)
+    {
+      unread = 1;
+      if (cur->msgno < min_unread_msgno)
+      {
+       min_unread = cur->virtual;
+       min_unread_msgno = cur->msgno;
+      }
+    }
+
+    if (cur->virtual == -1 && CHECK_LIMIT)
+      num_hidden++;
+
+    if (cur->child)
+      cur = cur->child;
+    else if (cur->next)
+      cur = cur->next;
+    else
+    {
+      int done = 0;
+      while (!cur->next)
+      {
+       cur = cur->parent;
+       if (cur == top)
+       {
+         done = 1;
+         break;
+       }
+      }
+      if (done)
+       break;
+      cur = cur->next;
+    }
+  }
+
+  /* return value depends on action requested */
+  if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE))
+    return (final);
+  else if (flag & M_THREAD_UNREAD)
+    return (unread);
+  else if (flag & M_THREAD_GET_HIDDEN)
+    return (num_hidden+1);
+  else if (flag & M_THREAD_NEXT_NEW)
+    return (min_unread);
+
+  return (0);
+#undef CHECK_LIMIT
+}
+