]> git.deb.at Git - pkg/abook.git/blobdiff - list.c
Upload 0.6.1-2 to unstable
[pkg/abook.git] / list.c
diff --git a/list.c b/list.c
index da6635e5a26d8da58784cff1bb153d32fe8254ca..1f0af7942c8fa4515c57ebaeacaec3a37cbed883 100644 (file)
--- a/list.c
+++ b/list.c
 #include "ui.h"
 #include "database.h"
 #include "edit.h"
+#include "gettext.h"
 #include "list.h"
 #include "misc.h"
 #include "options.h"
+#include "xmalloc.h"
+#include "color.h"
 
-#define MIN_EXTRA_COLUMN       ADDRESS /* 2 */
-#define MAX_EXTRA_COLUMN       LAST_FIELD
 
 int curitem = -1;
 int first_list_item = -1;
+int scroll_speed = 2;
 char *selected = NULL;
 
-int extra_column = -1;
-int extra_alternative = -1;
-
-extern int items;
-extern list_item *database;
-extern struct abook_field abook_fields[];
+extern abook_field_list *fields_list;
+struct index_elem *index_elements = NULL;
 
 static WINDOW *list = NULL;
 
-static int
-init_extra_field(enum str_opts option)
+
+static void
+index_elem_add(int type, char *a, char *b)
 {
-       int i, ret = -1;
-       char *option_str;
+       struct index_elem *tmp = NULL, *cur, *cur2;
+       int field, len = 0;
 
-       option_str = opt_get_str(option);
+       if(!a || !*a)
+               return;
 
-       if(option_str && *option_str) {
-               for(i = 0; i < ITEM_FIELDS; i++) {
-                       if(!strcasecmp(option_str, abook_fields[i].key)) {
-                               ret = i;
-                               break;
-                       }
-               }
-               if(ret < MIN_EXTRA_COLUMN || ret > MAX_EXTRA_COLUMN) {
-                       ret = -1;
-               }
+       switch(type) {
+               case INDEX_TEXT:
+                       tmp = xmalloc(sizeof(struct index_elem));
+                       tmp->d.text = xstrdup(a);
+                       break;
+               case INDEX_FIELD: /* fall through */
+               case INDEX_ALT_FIELD:
+                       find_field_number(a, &field);
+                       if(field == -1)
+                               return;
+                       len = (b && *b && is_number(b)) ? atoi(b) : 0;
+                       tmp = xmalloc(sizeof(struct index_elem));
+                       tmp->d.field.id = field;
+                       tmp->d.field.len = len;
+                       break;
+               default:
+                       assert(0);
        }
+       tmp->type = type;
+       tmp->next = NULL;
+       tmp->d.field.next = NULL;
 
-       return ret;
+       if(!index_elements) { /* first element */
+               index_elements = tmp;
+               return;
+       }
+
+       for(cur = index_elements; cur->next; cur = cur->next)
+               ;
+       if(type != INDEX_ALT_FIELD)
+               cur->next = tmp;
+       else { /* add as an alternate field */
+               tmp->d.field.len = cur->d.field.len;
+               for(cur2 = cur; cur2->d.field.next; cur2 = cur2->d.field.next)
+                       ;
+               cur2->d.field.next = tmp;
+       }
+}
+
+static void
+parse_index_format(char *s)
+{
+       char *p, *start, *lstart = NULL;
+       int in_field = 0, in_alternate = 0, in_length = 0, type;
+
+       p = start = s;
+
+       while(*p) {
+               if(*p == '{' && !in_field) {
+                       *p = 0;
+                       index_elem_add(INDEX_TEXT, start, NULL);
+                       start = ++p;
+                       in_field = 1;
+               } else if(*p == ':' && in_field && !in_alternate) {
+                       *p = 0;
+                       lstart = ++p;
+                       in_length = 1;
+               } else if(*p == '|' && in_field) {
+                       *p = 0;
+                       type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
+                       index_elem_add(type, start, in_length ? lstart : NULL);
+                       start = ++p;
+                       in_length = 0;
+                       in_alternate = 1;
+               } else if(*p == '}' && in_field) {
+                       *p = 0;
+                       type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
+                       index_elem_add(type, start, in_length ? lstart : NULL);
+                       start = ++p;
+                       in_field = in_alternate = in_length = 0;
+               } else
+                       p++;
+       }
+       if(!in_field)
+               index_elem_add(INDEX_TEXT, start, NULL);
+}
+
+void
+init_index()
+{
+       assert(!index_elements);
+       parse_index_format(opt_get_str(STR_INDEX_FORMAT));
 }
 
 void
@@ -62,13 +131,7 @@ init_list()
 {
        list = newwin(LIST_LINES, LIST_COLS, LIST_TOP, 0);
        scrollok(list, TRUE);
-
-       /*
-        * init extra_column and extra alternative
-        */
-
-       extra_column = init_extra_field(STR_EXTRA_COLUMN);
-       extra_alternative = init_extra_field(STR_EXTRA_ALTERNATIVE);
+       scroll_speed = abs(opt_get_int(INT_SCROLL_SPEED));
 }
 
 void
@@ -78,6 +141,124 @@ close_list()
        list = NULL;
 }
 
+void
+get_list_field(int item, struct index_elem *e, struct list_field *res)
+{
+       char *s;
+
+       res->data = s = NULL;
+
+       do { /* find first non-empty field data in the alternate fields list */
+               s = db_fget_byid(item, e->d.field.id);
+       } while(!(s && *s) && ((e = e->d.field.next) != NULL));
+
+       if(!e || !s || !*s)
+               return;
+
+       res->data = s;
+       get_field_info(e->d.field.id, NULL, NULL, &res->type);
+}
+
+static void
+print_list_field(int item, int line, int *x_pos, struct index_elem *e)
+{
+       char *s, *p;
+       int width, x_start, mustfree = FALSE, len = abs(e->d.field.len);
+       struct list_field f;
+
+       get_list_field(item, e, &f);
+       s = f.data;
+
+       if(!s || !*s) {
+               *x_pos += len;
+               return;
+       }
+       
+       if(f.type == FIELD_EMAILS && !opt_get_bool(BOOL_SHOW_ALL_EMAILS))
+               if((p = strchr(s, ',')) != NULL) {
+                       s = xstrndup(s, p - s);
+                       mustfree = TRUE;
+               }
+
+       width = len ? bytes2width(s, len) : strwidth(s);
+       x_start = *x_pos + ((e->d.field.len < 0) ? len - width : 0);
+       if(width + x_start >= COLS)
+               width = bytes2width(s, COLS - x_start);
+
+       if(width)
+               mvwaddnstr(list, line, x_start, s, width);
+
+       if(mustfree)
+               free(s);
+               
+       *x_pos += len ? len : width;
+}
+
+static void
+highlight_line(WINDOW *win, int line)
+{
+       wattrset(win, COLOR_PAIR(CP_LIST_HIGHLIGHT));
+       if(!opt_get_bool(BOOL_USE_COLORS)) {
+               wstandout(win);
+       }
+
+       /*
+        * this is a tricky one
+        */
+#if 0
+/*#ifdef mvwchgat*/
+       mvwchgat(win, line, 0, -1,  A_STANDOUT, 0, NULL);
+#else
+       /*
+        * buggy function: FIXME
+        */
+       scrollok(win, FALSE);
+       {
+               int i;
+               wmove(win, line, 0);
+               for(i = 0; i < COLS; i++)
+                       waddch(win, ' ');
+       /*wattrset(win, 0);*/
+       }
+       scrollok(win, TRUE);
+#endif
+}
+
+static void
+print_list_line(int item, int line, int highlight)
+{
+       struct index_elem *cur;
+       int x_pos = 1;
+
+       if(item % 2 == 0)
+               wattrset(list, COLOR_PAIR(CP_LIST_EVEN));
+       else
+               wattrset(list, COLOR_PAIR(CP_LIST_ODD));
+       scrollok(list, FALSE);
+       if(highlight)
+               highlight_line(list, line);
+
+       if(selected[item])
+               mvwaddch(list, line, 0, '*' );
+
+       for(cur = index_elements; cur; cur = cur->next)
+               switch(cur->type) {
+                       case INDEX_TEXT:
+                               mvwaddstr(list, line, x_pos, cur->d.text);
+                               x_pos += strwidth(cur->d.text);
+                               break;
+                       case INDEX_FIELD:
+                               print_list_field(item, line, &x_pos, cur);
+                               break;
+                       default:
+                               assert(0);
+               }
+
+       scrollok(list, TRUE);
+       if(highlight)
+               wstandend(list);
+}
+
 void
 refresh_list()
 {
@@ -104,8 +285,9 @@ refresh_list()
        else if(curitem > LAST_LIST_ITEM)
                first_list_item = max(curitem - LIST_LINES + 1, 0);
 
-        for( line = 0, i = first_list_item ; i <= LAST_LIST_ITEM && i < items;
-                       line++, i++ ) {
+        for(line = 0, i = first_list_item;
+                       i <= LAST_LIST_ITEM && i < db_n_items();
+                       line++, i++) {
 
                print_list_line(i, line, i == curitem);
         }
@@ -118,56 +300,33 @@ refresh_list()
         wrefresh(list);
 }
 
-void
-print_list_line(int i, int line, int highlight)
-{
-       int extra = extra_column;
-       char tmp[MAX_EMAILSTR_LEN];
-       int real_emaillen = (extra_column > 0 || extra_alternative > 0) ?
-               EMAILLEN : COLS - EMAILPOS;
-
-       scrollok(list, FALSE);
-       if(highlight)
-               highlight_line(list, line);
-
-       if(selected[i])
-               mvwaddch(list, line, 0, '*' );
-
-       mvwaddnstr(list, line, NAMEPOS, database[i][NAME],
-               bytes2width(database[i][NAME], NAMELEN));
-       if(opt_get_bool(BOOL_SHOW_ALL_EMAILS))
-               mvwaddnstr(list, line, EMAILPOS, database[i][EMAIL],
-                               bytes2width(database[i][EMAIL], real_emaillen));
-       else {
-               get_first_email(tmp, i);
-               mvwaddnstr(list, line, EMAILPOS, tmp,
-                       bytes2width(tmp, real_emaillen));
-       }
-
-       if(extra < 0 || !database[i][extra])
-               extra = extra_alternative;
-       if(extra >= 0)
-               mvwaddnstr(list, line, EXTRAPOS,
-                       safe_str(database[i][extra]),
-                       bytes2width(safe_str(database[i][extra]), EXTRALEN));
-
-       scrollok(list, TRUE);
-       if(highlight)
-               wstandend(list);
-}
-
-
 void
 list_headerline()
 {
+       struct index_elem *e;
+       int x_pos = 1, width;
+       char *str = NULL;
+
 #if defined(A_BOLD) && defined(A_NORMAL)
        attrset(A_BOLD);
 #endif
-       mvaddstr(2, NAMEPOS, abook_fields[NAME].name);
-       mvaddstr(2, EMAILPOS, abook_fields[EMAIL].name);
-       if(extra_column > 0)
-               mvaddnstr(2, EXTRAPOS, abook_fields[extra_column].name,
-                               COLS-EXTRAPOS);
+       attrset(COLOR_PAIR(CP_LIST_HEADER));
+       mvhline(2, 0, ' ', COLS);
+
+       for(e = index_elements; e; e = e->next)
+               if(e->type == INDEX_TEXT)
+                       x_pos += strwidth(e->d.text);
+               else if(e->type == INDEX_FIELD) {
+                       get_field_info(e->d.field.id, NULL, &str, NULL);
+                       width = e->d.field.len ?
+                               abs(e->d.field.len) : strwidth(str);
+                       if(width + x_pos > COLS)
+                               width = bytes2width(str, COLS - x_pos);
+                       mvaddnstr(2, x_pos, str, width);
+                       x_pos += width;
+               } else
+                       assert(0);
+
 #if defined(A_BOLD) && defined(A_NORMAL)
        attrset(A_NORMAL);
 #endif
@@ -187,7 +346,7 @@ scroll_up()
 void
 scroll_down()
 {
-       if(curitem > items - 2)
+       if(curitem > db_n_items() - 2)
                return;
 
        curitem++;
@@ -195,6 +354,49 @@ scroll_down()
        refresh_list();
 }
 
+void
+scroll_list_up()
+{
+       if(first_list_item <= 0) {
+               if(curitem != 0) {
+                       curitem--;
+                       refresh_list();
+               }
+               return;
+       }
+
+       first_list_item -= scroll_speed;
+       if(first_list_item < 0) {
+               first_list_item = 0;
+       }
+       if(curitem > LAST_LIST_ITEM) {
+               curitem = LAST_LIST_ITEM;
+       }
+
+       refresh_list();
+}
+
+void
+scroll_list_down()
+{
+       if(LAST_LIST_ITEM > db_n_items() - 2) {
+               if(curitem < LAST_LIST_ITEM) {
+                       curitem++;
+                       refresh_list();
+               }
+               return;
+       }
+
+       first_list_item += scroll_speed;
+       if(LAST_LIST_ITEM > db_n_items() - 1) {
+               first_list_item = db_n_items() - LIST_LINES;
+       }
+       if(curitem < first_list_item) {
+               curitem = first_list_item;
+       }
+
+       refresh_list();
+}
 
 void
 page_up()
@@ -211,12 +413,15 @@ page_up()
 void
 page_down()
 {
-       if(curitem > items - 2)
+       if(curitem > db_n_items() - 2)
                return;
 
-       curitem = curitem == LAST_LIST_ITEM ?
-               ((curitem += LIST_LINES) > LAST_ITEM ? LAST_ITEM : curitem) :
-               min(LAST_LIST_ITEM, LAST_ITEM);
+       if(curitem == LAST_LIST_ITEM) {
+               if((curitem += LIST_LINES) > last_item())
+                       curitem = last_item();
+       } else {
+               curitem = min(LAST_LIST_ITEM, last_item());
+       }
 
        refresh_list();
 }
@@ -224,13 +429,29 @@ page_down()
 void
 select_none()
 {
-        memset(selected, 0, items);
+        memset(selected, 0, db_n_items());
 }
 
 void
 select_all()
 {
-        memset(selected, 1, items);
+        memset(selected, 1, db_n_items());
+}
+
+void
+list_set_selection(int item, int value)
+{
+       assert(is_valid_item(item));
+
+       selected[item] = !!value;
+}
+
+void
+list_invert_curitem_selection()
+{
+       assert(is_valid_item(curitem));
+
+       selected[curitem] = !selected[curitem];
 }
 
 void
@@ -238,34 +459,40 @@ move_curitem(int direction)
 {
         list_item tmp;
 
-        if( curitem < 0 || curitem > LAST_ITEM )
+        if(curitem < 0 || curitem > last_item())
                 return;
 
-        itemcpy(tmp, database[curitem]);
-
-        switch(direction) {
-                case MOVE_ITEM_UP:
-                        if( curitem < 1 )
-                                return;
-                        itemcpy(database[curitem], database[curitem - 1]);
-                        itemcpy(database[curitem-1], tmp);
-                        scroll_up();
-                        break;
-
-                case MOVE_ITEM_DOWN:
-                        if( curitem >= LAST_ITEM )
-                                return;
-                        itemcpy(database[curitem], database[curitem + 1]);
-                        itemcpy(database[curitem+1], tmp);
-                        scroll_down();
-                        break;
-        }
+       tmp = item_create();
+       item_copy(tmp, db_item_get(curitem));
+
+       switch(direction) {
+               case MOVE_ITEM_UP:
+                       if( curitem < 1 )
+                               goto out_move;
+                       item_copy(db_item_get(curitem),
+                                       db_item_get(curitem - 1));
+                       item_copy(db_item_get(curitem-1), tmp);
+                       scroll_up();
+                       break;
+
+               case MOVE_ITEM_DOWN:
+                       if(curitem >= last_item())
+                               goto out_move;
+                       item_copy(db_item_get(curitem),
+                                       db_item_get(curitem + 1));
+                       item_copy(db_item_get(curitem + 1), tmp);
+                       scroll_down();
+                       break;
+       }
+
+out_move:
+       item_free(&tmp);
 }
 
 void
 goto_home()
 {
-       if(items > 0)
+       if(db_n_items() > 0)
                curitem = 0;
 
        refresh_list();
@@ -274,46 +501,18 @@ goto_home()
 void
 goto_end()
 {
-       if(items > 0)
-               curitem = LAST_ITEM;
+       if(db_n_items() > 0)
+               curitem = last_item();
 
        refresh_list();
 }
 
-
-void
-highlight_line(WINDOW *win, int line)
-{
-       wstandout(win);
-
-       /*
-        * this is a tricky one
-        */
-#if 0
-/*#ifdef mvwchgat*/
-       mvwchgat(win, line, 0, -1,  A_STANDOUT, 0, NULL);
-#else
-       /*
-        * buggy function: FIXME
-        */
-       scrollok(win, FALSE);
-       {
-               int i;
-               wmove(win, line, 0);
-               for(i = 0; i < COLS; i++)
-                       waddch(win, ' ');
-       /*wattrset(win, 0);*/
-       }
-       scrollok(win, TRUE);
-#endif
-}
-
 int
 selected_items()
 {
        int i, n = 0;
 
-       for(i = 0; i < items; i++)
+       for(i = 0; i < db_n_items(); i++)
                if(selected[i])
                        n++;
 
@@ -325,42 +524,54 @@ invert_selection()
 {
        int i;
 
-       if(items < 1)
+       if(list_is_empty())
                return;
 
-       for(i = 0; i < items; i++)
+       for(i = 0; i < db_n_items(); i++)
                selected[i] = !selected[i];
 }
 
 int
-list_current_item()
+list_is_empty()
+{
+       return db_n_items() < 1;
+}
+
+int
+list_get_curitem()
 {
        return curitem;
 }
 
 int
-list_is_empty()
+list_get_firstitem()
 {
-       return items < 1;
+       return first_list_item;
+}
+
+void
+list_set_curitem(int i)
+{
+       curitem = i;
 }
 
 int
 duplicate_item()
 {
-       int i;
        list_item item;
-
+       
        if(curitem < 0)
                return 1;
 
-       for(i = 0; i < ITEM_FIELDS; i++)
-               item[i] = database[curitem][i] ? strdup(database[curitem][i]) :
-                       NULL;
-
-       if(add_item2database(item))
+       item = item_create();
+       item_duplicate(item, db_item_get(curitem));
+       if(add_item2database(item)) {
+               item_free(&item);
                return 1;
+       }
+       item_free(&item);
 
-       curitem = LAST_ITEM;
+       curitem = last_item();
        refresh_list();
 
        return 0;