Initialize with abook-0.6.0pre2
[abook.git] / list.c
bloba6d442f249f1b260098effd75b48ca6bfa5f8b72
2 /*
3 * $Id: list.c,v 1.33 2006/09/05 08:21:35 jheinonen Exp $
5 * by JH <jheinonen@users.sourceforge.net>
7 * Copyright (C) Jaakko Heinonen
8 */
10 #include <stdio.h>
11 #include <string.h>
12 #include "abook.h"
13 #include <assert.h>
14 #include "ui.h"
15 #include "database.h"
16 #include "edit.h"
17 #include "gettext.h"
18 #include "list.h"
19 #include "misc.h"
20 #include "options.h"
21 #include "xmalloc.h"
24 int curitem = -1;
25 int first_list_item = -1;
26 char *selected = NULL;
28 extern abook_field_list *fields_list;
29 struct index_elem *index_elements = NULL;
31 static WINDOW *list = NULL;
34 static void
35 index_elem_add(int type, char *a, char *b)
37 struct index_elem *tmp = NULL, *cur, *cur2;
38 int field, len = 0;
40 if(!a || !*a)
41 return;
43 switch(type) {
44 case INDEX_TEXT:
45 tmp = xmalloc(sizeof(struct index_elem));
46 tmp->d.text = xstrdup(a);
47 break;
48 case INDEX_FIELD: /* fall through */
49 case INDEX_ALT_FIELD:
50 find_field_number(a, &field);
51 if(field == -1)
52 return;
53 len = (b && *b && is_number(b)) ? atoi(b) : 0;
54 tmp = xmalloc(sizeof(struct index_elem));
55 tmp->d.field.id = field;
56 tmp->d.field.len = len;
57 break;
58 default:
59 assert(0);
61 tmp->type = type;
62 tmp->next = NULL;
63 tmp->d.field.next = NULL;
65 if(!index_elements) { /* first element */
66 index_elements = tmp;
67 return;
70 for(cur = index_elements; cur->next; cur = cur->next)
72 if(type != INDEX_ALT_FIELD)
73 cur->next = tmp;
74 else { /* add as an alternate field */
75 tmp->d.field.len = cur->d.field.len;
76 for(cur2 = cur; cur2->d.field.next; cur2 = cur2->d.field.next)
78 cur2->d.field.next = tmp;
82 static void
83 parse_index_format(char *s)
85 char *p, *start, *lstart = NULL;
86 int in_field = 0, in_alternate = 0, in_length = 0, type;
88 p = start = s;
90 while(*p) {
91 if(*p == '{' && !in_field) {
92 *p = 0;
93 index_elem_add(INDEX_TEXT, start, NULL);
94 start = ++p;
95 in_field = 1;
96 } else if(*p == ':' && in_field && !in_alternate) {
97 *p = 0;
98 lstart = ++p;
99 in_length = 1;
100 } else if(*p == '|' && in_field) {
101 *p = 0;
102 type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
103 index_elem_add(type, start, in_length ? lstart : NULL);
104 start = ++p;
105 in_length = 0;
106 in_alternate = 1;
107 } else if(*p == '}' && in_field) {
108 *p = 0;
109 type = in_alternate ? INDEX_ALT_FIELD : INDEX_FIELD;
110 index_elem_add(type, start, in_length ? lstart : NULL);
111 start = ++p;
112 in_field = in_alternate = in_length = 0;
113 } else
114 p++;
116 if(!in_field)
117 index_elem_add(INDEX_TEXT, start, NULL);
120 void
121 init_index()
123 assert(!index_elements);
124 parse_index_format(opt_get_str(STR_INDEX_FORMAT));
127 void
128 init_list()
130 list = newwin(LIST_LINES, LIST_COLS, LIST_TOP, 0);
131 scrollok(list, TRUE);
134 void
135 close_list()
137 delwin(list);
138 list = NULL;
141 void
142 get_list_field(int item, struct index_elem *e, struct list_field *res)
144 char *s;
146 res->data = s = NULL;
148 do { /* find first non-empty field data in the alternate fields list */
149 s = db_fget_byid(item, e->d.field.id);
150 } while(!(s && *s) && ((e = e->d.field.next) != NULL));
152 if(!e || !s || !*s)
153 return;
155 res->data = s;
156 get_field_info(e->d.field.id, NULL, NULL, &res->type);
159 static void
160 print_list_field(int item, int line, int *x_pos, struct index_elem *e)
162 char *s, *p;
163 int width, x_start, mustfree = FALSE, len = abs(e->d.field.len);
164 struct list_field f;
166 get_list_field(item, e, &f);
167 s = f.data;
169 if(!s || !*s) {
170 *x_pos += len;
171 return;
174 if(f.type == FIELD_EMAILS && !opt_get_bool(BOOL_SHOW_ALL_EMAILS))
175 if((p = strchr(s, ',')) != NULL) {
176 s = xstrndup(s, p - s);
177 mustfree = TRUE;
180 width = len ? bytes2width(s, len) : strwidth(s);
181 x_start = *x_pos + ((e->d.field.len < 0) ? len - width : 0);
182 if(width + x_start >= COLS)
183 width = COLS - x_start;
185 if(width)
186 mvwaddnstr(list, line, x_start, s, width);
188 if(mustfree)
189 free(s);
191 *x_pos += len ? len : width;
194 static void
195 highlight_line(WINDOW *win, int line)
197 wstandout(win);
200 * this is a tricky one
202 #if 0
203 /*#ifdef mvwchgat*/
204 mvwchgat(win, line, 0, -1, A_STANDOUT, 0, NULL);
205 #else
207 * buggy function: FIXME
209 scrollok(win, FALSE);
211 int i;
212 wmove(win, line, 0);
213 for(i = 0; i < COLS; i++)
214 waddch(win, ' ');
215 /*wattrset(win, 0);*/
217 scrollok(win, TRUE);
218 #endif
221 static void
222 print_list_line(int item, int line, int highlight)
224 struct index_elem *cur;
225 int x_pos = 1;
227 scrollok(list, FALSE);
228 if(highlight)
229 highlight_line(list, line);
231 if(selected[item])
232 mvwaddch(list, line, 0, '*' );
234 for(cur = index_elements; cur; cur = cur->next)
235 switch(cur->type) {
236 case INDEX_TEXT:
237 mvwaddstr(list, line, x_pos, cur->d.text);
238 x_pos += strwidth(cur->d.text);
239 break;
240 case INDEX_FIELD:
241 print_list_field(item, line, &x_pos, cur);
242 break;
243 default:
244 assert(0);
247 scrollok(list, TRUE);
248 if(highlight)
249 wstandend(list);
252 void
253 refresh_list()
255 int i, line;
257 werase(list);
259 ui_print_number_of_items();
261 if(list_is_empty()) {
262 refresh();
263 wrefresh(list);
264 return;
267 if(curitem < 0)
268 curitem = 0;
270 if(first_list_item < 0)
271 first_list_item = 0;
273 if(curitem < first_list_item)
274 first_list_item = curitem;
275 else if(curitem > LAST_LIST_ITEM)
276 first_list_item = max(curitem - LIST_LINES + 1, 0);
278 for(line = 0, i = first_list_item;
279 i <= LAST_LIST_ITEM && i < db_n_items();
280 line++, i++) {
282 print_list_line(i, line, i == curitem);
285 if(opt_get_bool(BOOL_SHOW_CURSOR)) {
286 wmove(list, curitem - first_list_item, 0);
287 /* need to call refresh() to update the cursor positions */
288 refresh();
290 wrefresh(list);
293 void
294 list_headerline()
296 struct index_elem *e;
297 int x_pos = 1, width;
298 char *str = NULL;
300 #if defined(A_BOLD) && defined(A_NORMAL)
301 attrset(A_BOLD);
302 #endif
304 for(e = index_elements; e; e = e->next)
305 if(e->type == INDEX_TEXT)
306 x_pos += strwidth(e->d.text);
307 else if(e->type == INDEX_FIELD) {
308 get_field_info(e->d.field.id, NULL, &str, NULL);
309 width = e->d.field.len ? abs(e->d.field.len) : strwidth(str);
310 mvaddnstr(2, x_pos, str, width);
311 x_pos += width;
312 } else
313 assert(0);
315 #if defined(A_BOLD) && defined(A_NORMAL)
316 attrset(A_NORMAL);
317 #endif
320 void
321 scroll_up()
323 if(curitem < 1)
324 return;
326 curitem--;
328 refresh_list();
331 void
332 scroll_down()
334 if(curitem > db_n_items() - 2)
335 return;
337 curitem++;
339 refresh_list();
343 void
344 page_up()
346 if(curitem < 1)
347 return;
349 curitem = curitem == first_list_item ?
350 ((curitem -= LIST_LINES) < 0 ? 0 : curitem) : first_list_item;
352 refresh_list();
355 void
356 page_down()
358 if(curitem > db_n_items() - 2)
359 return;
361 if(curitem == LAST_LIST_ITEM) {
362 if((curitem += LIST_LINES) > last_item())
363 curitem = last_item();
364 } else {
365 curitem = min(LAST_LIST_ITEM, last_item());
368 refresh_list();
371 void
372 select_none()
374 memset(selected, 0, db_n_items());
377 void
378 select_all()
380 memset(selected, 1, db_n_items());
383 void
384 list_set_selection(int item, int value)
386 assert(is_valid_item(item));
388 selected[item] = !!value;
391 void
392 list_invert_curitem_selection()
394 assert(is_valid_item(curitem));
396 selected[curitem] = !selected[curitem];
399 void
400 move_curitem(int direction)
402 list_item tmp;
404 if(curitem < 0 || curitem > last_item())
405 return;
407 tmp = item_create();
408 item_copy(tmp, db_item_get(curitem));
410 switch(direction) {
411 case MOVE_ITEM_UP:
412 if( curitem < 1 )
413 goto out_move;
414 item_copy(db_item_get(curitem),
415 db_item_get(curitem - 1));
416 item_copy(db_item_get(curitem-1), tmp);
417 scroll_up();
418 break;
420 case MOVE_ITEM_DOWN:
421 if(curitem >= last_item())
422 goto out_move;
423 item_copy(db_item_get(curitem),
424 db_item_get(curitem + 1));
425 item_copy(db_item_get(curitem + 1), tmp);
426 scroll_down();
427 break;
430 out_move:
431 item_free(&tmp);
434 void
435 goto_home()
437 if(db_n_items() > 0)
438 curitem = 0;
440 refresh_list();
443 void
444 goto_end()
446 if(db_n_items() > 0)
447 curitem = last_item();
449 refresh_list();
453 selected_items()
455 int i, n = 0;
457 for(i = 0; i < db_n_items(); i++)
458 if(selected[i])
459 n++;
461 return n;
464 void
465 invert_selection()
467 int i;
469 if(list_is_empty())
470 return;
472 for(i = 0; i < db_n_items(); i++)
473 selected[i] = !selected[i];
477 list_is_empty()
479 return db_n_items() < 1;
483 list_get_curitem()
485 return curitem;
488 void
489 list_set_curitem(int i)
491 curitem = i;
495 duplicate_item()
497 list_item item;
499 if(curitem < 0)
500 return 1;
502 item = item_create();
503 item_duplicate(item, db_item_get(curitem));
504 if(add_item2database(item)) {
505 item_free(&item);
506 return 1;
508 item_free(&item);
510 curitem = last_item();
511 refresh_list();
513 return 0;