Andreas Krennmair:
[apps/madmutt.git] / sidebar.c
1 /*
2  * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
3  * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
4  * 
5  *     This program is free software; you can redistribute it and/or modify
6  *     it under the terms of the GNU General Public License as published by
7  *     the Free Software Foundation; either version 2 of the License, or
8  *     (at your option) any later version.
9  * 
10  *     This program is distributed in the hope that it will be useful,
11  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *     GNU General Public License for more details.
14  * 
15  *     You should have received a copy of the GNU General Public License
16  *     along with this program; if not, write to the Free Software
17  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
18  */ 
19
20
21
22 #include "mutt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
25 #include "sidebar.h"
26 #include "buffy.h"
27 #include <libgen.h>
28 #include "keymap.h"
29 #include <stdbool.h>
30 #include <ctype.h>
31
32 /*BUFFY *CurBuffy = 0;*/
33 static BUFFY *TopBuffy = 0;
34 static BUFFY *BottomBuffy = 0;
35 static int known_lines = 0;
36 static bool initialized = false;
37 static int prev_show_value;
38 static short saveSidebarWidth;
39 static char *entry = 0;
40
41 static int quick_log10(int n)
42 {
43   int len = 0;
44   for (; n > 9; len++, n /= 10)
45     ;
46   return (++len);
47 }
48
49 static int cur_is_hidden (int maxline)
50 {
51   int l = 0, seen = 0;
52   BUFFY* tmp = TopBuffy;
53   if (!CurBuffy)
54     return (0);
55   while (tmp && l < maxline && !seen)
56   {
57     if (strcmp (tmp->path, CurBuffy->path) == 0)
58       seen = 1;
59     else
60       tmp = tmp->next;
61     l++;
62   }
63   return (seen == 0 || l == maxline);
64 }
65
66 void calc_boundaries (int menu)
67 {
68   BUFFY *tmp = Incoming;
69
70   if ( known_lines != LINES ) {
71     TopBuffy = BottomBuffy = 0;
72     known_lines = LINES;
73   }
74   for ( ; tmp->next != 0; tmp = tmp->next )
75     tmp->next->prev = tmp;
76
77   if ( TopBuffy == 0 && BottomBuffy == 0 )
78     TopBuffy = Incoming;
79   if ( BottomBuffy == 0 ) {
80     int count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
81     BottomBuffy = TopBuffy;
82     while ( --count && BottomBuffy->next )
83       BottomBuffy = BottomBuffy->next;
84   }
85   else if ( TopBuffy == CurBuffy->next ) {
86     int count = LINES - 2 - (menu != MENU_PAGER);
87     BottomBuffy = CurBuffy;
88     tmp = BottomBuffy;
89     while ( --count && tmp->prev)
90       tmp = tmp->prev;
91     TopBuffy = tmp;
92   }
93   else if ( BottomBuffy == CurBuffy->prev ) {
94     int count = LINES - 2 - (menu != MENU_PAGER);
95     TopBuffy = CurBuffy;
96     tmp = TopBuffy;
97     while ( --count && tmp->next )
98       tmp = tmp->next;
99     BottomBuffy = tmp;
100   }
101 }
102
103 static char * shortened_hierarchy(char * box) {
104   int dots = 0;
105   char * last_dot;
106   int i,j;
107   char * new_box;
108   for (i=0;i<strlen(box);++i) {
109     if (box[i] == '.') ++dots;
110     else if (isupper (box[i])) 
111       return (safe_strdup (box));
112   }
113   last_dot = strrchr(box,'.');
114   if (last_dot) {
115     ++last_dot;
116     new_box = safe_malloc(strlen(last_dot)+2*dots+1);
117     new_box[0] = box[0];
118     for (i=1,j=1;i<strlen(box);++i) {
119       if (box[i] == '.') {
120         new_box[j++] = '.';
121         new_box[j] = 0;
122         if (&box[i+1] != last_dot) {
123           new_box[j++] = box[i+1];
124           new_box[j] = 0;
125         } else {
126           strcat(&new_box[j],last_dot);
127           break;
128         }
129       }
130     }
131     return new_box;
132   }
133   return safe_strdup(box);
134 }
135
136 char *make_sidebar_entry(char *box, int size, int new, int flagged)
137 {
138   char *c;
139   int i = 0, dlen = mutt_strlen (SidebarDelim), max = SidebarWidth-dlen-1,
140       shortened = 0;
141
142   c = realloc(entry, SidebarWidth + 1);
143   if ( c ) entry = c;
144   entry[SidebarWidth] = 0;
145   for (; i < SidebarWidth; entry[i++] = ' ' );
146 #if USE_IMAP
147   if (ImapHomeNamespace && strlen(ImapHomeNamespace)>0) {
148     if (strncmp(box,ImapHomeNamespace,strlen(ImapHomeNamespace))==0 && strcmp(box,ImapHomeNamespace)!=0) {
149       box+=strlen(ImapHomeNamespace)+1;
150     }
151   }
152 #endif
153   max -= quick_log10(size);
154   if (new)
155     max -= quick_log10(new) + 2;
156   if (flagged > 0)
157     max -= quick_log10(flagged) + 2;
158   if (option(OPTSHORTENHIERARCHY) && mutt_strlen(box) > max) {
159     box = shortened_hierarchy(box);
160     shortened = 1;
161   }
162   i = strlen(box);
163   strncpy( entry, box, i < SidebarWidth - dlen ? i :SidebarWidth - dlen);
164
165   if ( new ) {
166     if (flagged>0) {
167       sprintf(entry + SidebarWidth - 5 - quick_log10(size) - dlen - quick_log10(new) - quick_log10(flagged),
168               "% d(%d)[%d]", size, new, flagged);
169     } else {
170       sprintf(entry + SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(new),
171               "% d(%d)", size, new);
172     }
173   } else {
174     if (flagged>0) {
175       sprintf( entry + SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(flagged), "% d[%d]", size,flagged);
176     } else {
177       sprintf( entry + SidebarWidth - 1 - quick_log10(size) - dlen, "% d", size);
178     }
179
180   }
181   if (option(OPTSHORTENHIERARCHY) && shortened) {
182     free(box);
183   }
184   return entry;
185 }
186
187 void set_curbuffy(char buf[LONG_STRING])
188 {
189   BUFFY* tmp = CurBuffy = Incoming;
190
191   if (!Incoming)
192     return;
193
194   while(1) {
195     if(!strcmp(tmp->path, buf)) {
196       CurBuffy = tmp;
197       break;
198     }
199
200     if(tmp->next)
201       tmp = tmp->next;
202     else
203       break;
204   }
205 }
206
207 void set_buffystats (CONTEXT* Context)
208 {
209   BUFFY* tmp = Incoming;
210   while (tmp)
211   {
212     if (strcmp (tmp->path, Context->path) == 0)
213     {
214       tmp->msg_unread = Context->unread;
215       tmp->msgcount = Context->msgcount;
216       tmp->msg_flagged = Context->flagged;
217       break;
218     }
219     tmp = tmp->next;
220   }
221 }
222
223 int draw_sidebar(int menu) {
224
225   int lines = option(OPTHELP) ? 1 : 0;
226   BUFFY *tmp;
227   short delim_len = mutt_strlen (SidebarDelim);
228
229   /* initialize first time */
230   if(!initialized) {
231     prev_show_value = option(OPTMBOXPANE);
232     saveSidebarWidth = SidebarWidth;
233     if(!option(OPTMBOXPANE)) SidebarWidth = 0;
234     initialized = true;
235   }
236
237   /* save or restore the value SidebarWidth */
238   if(prev_show_value != option(OPTMBOXPANE)) {
239     if(prev_show_value && !option(OPTMBOXPANE)) {
240       saveSidebarWidth = SidebarWidth;
241       SidebarWidth = 0;
242     } else if(!prev_show_value && option(OPTMBOXPANE)) {
243       SidebarWidth = saveSidebarWidth;
244     }
245     prev_show_value = option(OPTMBOXPANE);
246   }
247
248   if ( SidebarWidth == 0 ) return 0;
249
250   /* draw the divider */
251   SETCOLOR(MT_COLOR_STATUS);
252   for (lines = option (OPTSTATUSONTOP) ? 0 : 1; 
253        lines < LINES-1-(menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
254     move(lines, SidebarWidth - delim_len);
255     addstr (NONULL (SidebarDelim));
256   }
257   SETCOLOR(MT_COLOR_NORMAL);
258
259   if ( Incoming == 0 ) return 0;
260   lines = option(OPTHELP) ? 1 : 0; /* go back to the top */
261
262   if (cur_is_hidden (LINES-1-(menu != MENU_PAGER)))
263     CurBuffy = TopBuffy;
264
265   if ( known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0 ) 
266     calc_boundaries(menu);
267   if ( CurBuffy == 0 ) CurBuffy = Incoming;
268
269   tmp = TopBuffy;
270
271   for ( ; tmp && lines < LINES-1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); tmp = tmp->next ) {
272     if ( tmp == CurBuffy )
273       SETCOLOR(MT_COLOR_INDICATOR);
274     else if ( tmp->msg_flagged > 0 )
275       SETCOLOR(MT_COLOR_FLAGGED);
276     else if ( tmp->msg_unread > 0 )
277       SETCOLOR(MT_COLOR_NEW);
278     else
279       SETCOLOR(MT_COLOR_NORMAL);
280
281     move( lines, 0 );
282     if ( Context && !strcmp( tmp->path, Context->path ) ) {
283       printw( "%.*s", SidebarWidth - delim_len,
284               make_sidebar_entry(basename(tmp->path),
285                                  Context->msgcount, Context->unread, Context->flagged));
286       tmp->msg_unread = Context->unread;
287       tmp->msgcount = Context->msgcount;
288       tmp->msg_flagged = Context->flagged;
289     }
290     else
291       printw( "%.*s", SidebarWidth - delim_len,
292               make_sidebar_entry(basename(tmp->path),
293                                  tmp->msgcount,tmp->msg_unread, tmp->msg_flagged));
294     lines++;
295   }
296   SETCOLOR(MT_COLOR_NORMAL);
297   for ( ; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
298     int i = 0;
299     move( lines, 0 );
300     for ( ; i < SidebarWidth - delim_len; i++ )
301       addch(' ');
302   }
303   return 0;
304 }
305
306 BUFFY * exist_next_new()
307 {
308         BUFFY *tmp = CurBuffy;
309         if(tmp == NULL) return NULL;
310         while (tmp->next != NULL)
311         {
312                 tmp = tmp->next;
313                 if(tmp->msg_unread) return tmp;
314         }
315         return NULL;
316 }
317
318 BUFFY * exist_prev_new()
319 {
320         BUFFY *tmp = CurBuffy;
321         if(tmp == NULL) return NULL;
322         while (tmp->prev != NULL)
323         {
324                 tmp = tmp->prev;
325                 if(tmp->msg_unread) return tmp;
326         }
327         return NULL;
328 }     
329
330
331 void scroll_sidebar(int op, int menu)
332 {
333   BUFFY *tmp;
334
335   if(!SidebarWidth) return;
336   if(!CurBuffy) return;
337
338   switch (op) {
339     case OP_SIDEBAR_NEXT:
340       if ( CurBuffy->next == NULL ) return;
341       CurBuffy = CurBuffy->next;
342       break;
343     case OP_SIDEBAR_NEXT_NEW:
344       if ( (tmp = exist_next_new()) == NULL)
345       {
346               if (CurBuffy->next == NULL) return;
347               CurBuffy = CurBuffy->next;
348       }
349       else CurBuffy = tmp;
350       break;
351     case OP_SIDEBAR_PREV:
352       if ( CurBuffy->prev == NULL ) return;
353       CurBuffy = CurBuffy->prev;
354      break;
355     case OP_SIDEBAR_PREV_NEW:
356       if ( (tmp = exist_prev_new()) == NULL)
357       {
358               if(CurBuffy->prev == NULL) return;
359               CurBuffy = CurBuffy->prev;
360       }
361       else CurBuffy = tmp;
362       break;
363      
364     case OP_SIDEBAR_SCROLL_UP:
365       CurBuffy = TopBuffy;
366       if ( CurBuffy != Incoming ) {
367         calc_boundaries(menu);
368         CurBuffy = CurBuffy->prev;
369       }
370       break;
371     case OP_SIDEBAR_SCROLL_DOWN:
372       CurBuffy = BottomBuffy;
373       if ( CurBuffy->next ) {
374         calc_boundaries(menu);
375         CurBuffy = CurBuffy->next;
376       }
377       break;
378     default:
379       return;
380   }
381   calc_boundaries(menu);
382   draw_sidebar(menu);
383 }