]> git.deb.at Git - pkg/abook.git/blob - ui.c
Merged first 0.4.13pre patch
[pkg/abook.git] / ui.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@bigfoot.com>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include "abook.h"
17 #include "ui.h"
18 #include "edit.h"
19 #include "database.h"
20 #include "list.h"
21 #include "misc.h"
22 #include "options.h"
23 #include "filter.h"
24 #include "estr.h"
25 #ifdef HAVE_CONFIG_H
26 #       include "config.h"
27 #endif
28 #ifdef HAVE_TERMIOS_H
29 #       include <termios.h>
30 #else
31 #       ifdef HAVE_LINUX_TERMIOS_H
32 #               include <linux/termios.h>
33 #       endif
34 #endif
35 #ifdef HAVE_SYS_IOCTL_H
36 #       include <sys/ioctl.h>
37 #endif
38
39 #ifdef USE_ASCII_ONLY
40 #       define UI_HLINE_CHAR            '-'
41 #else
42 #       define UI_HLINE_CHAR            ACS_HLINE
43 #endif
44
45
46 /*
47  * external variables
48  */
49
50 extern int items, curitem;
51 extern char *datafile;
52
53 /*
54  * internal variables
55  */
56
57 int ui_initialized = FALSE;
58
59 int should_resize = FALSE;
60 int can_resize = FALSE;
61
62 WINDOW *top = NULL, *bottom = NULL;
63
64
65
66 static void
67 init_windows()
68 {
69         top = newwin(LIST_TOP - 1, COLS, 0, 0);
70         
71         bottom = newwin(LINES - LIST_BOTTOM, COLS, LIST_BOTTOM, 0);
72 }
73
74 static void
75 free_windows()
76 {
77         delwin(top);
78         delwin(bottom);
79 }
80
81
82 #ifdef SIGWINCH
83 static void
84 resize_abook()
85 {
86 #ifdef TIOCGWINSZ
87         struct winsize winsz;
88
89         ioctl (0, TIOCGWINSZ, &winsz);
90 #ifdef DEBUG
91         if(winsz.ws_col >= MIN_COLS && winsz.ws_row >= MIN_LINES) {
92                 fprintf(stderr, "Warning: COLS=%d, LINES=%d\n", winsz.ws_col, winsz.ws_row);
93         }
94 #endif
95                 
96         if(winsz.ws_col >= MIN_COLS && winsz.ws_row >= MIN_LINES) {
97 #ifdef HAVE_RESIZETERM
98                 resizeterm(winsz.ws_row, winsz.ws_col);
99 #else
100                 COLS = winsz.ws_col;
101                 LINES = winsz.ws_row;
102 #endif
103         }
104
105         should_resize = FALSE;
106         close_list(); /* we need to recreate windows */
107         init_list();
108         free_windows();
109         init_windows();
110         refresh_screen();
111         refresh();
112 #endif /* TIOCGWINSZ */
113 }
114
115
116 static void
117 win_changed(int i)
118 {
119         if( can_resize )
120                 resize_abook();
121         else
122                 should_resize = TRUE;   
123 }
124 #endif /* SIGWINCH */
125
126
127 int
128 is_ui_initialized()
129 {
130         return ui_initialized;
131 }
132
133
134 int
135 init_ui()
136 {
137         initscr(); cbreak(); noecho();
138         nonl();
139         intrflush(stdscr, FALSE);
140         keypad(stdscr, TRUE);
141 #ifdef DEBUG
142         fprintf(stderr, "init_abook():\n");
143         fprintf(stderr, "  COLS = %d, LINES = %d\n", COLS, LINES);
144 #endif
145         if( LINES < MIN_LINES || COLS < MIN_COLS ) {
146                 clear(); refresh(); endwin();
147                 fprintf(stderr, "Your terminal size is %dx%d\n", COLS, LINES);
148                 fprintf(stderr, "Terminal is too small. Minium terminal size "
149                                 "for abook is "
150                                 "%dx%d\n", MIN_COLS, MIN_LINES);
151                 return 1;
152         }
153
154 #ifdef SIGWINCH
155         signal(SIGWINCH, win_changed);
156 #endif
157
158         init_list();
159         init_windows();
160
161         ui_initialized = TRUE;
162
163         return 0;
164 }
165
166 void
167 close_ui()
168 {
169         close_list();
170         free_windows();
171         clear();
172         refresh();
173         endwin();
174
175         ui_initialized = FALSE;
176 }
177
178
179 void
180 headerline(char *str)
181 {
182         werase(top);
183         
184         mvwhline(top, 1, 0, UI_HLINE_CHAR, COLS);
185         
186         mvwprintw(top, 0, 0, "%s | %s", PACKAGE " " VERSION, str);
187
188         refresh();
189         wrefresh(top);
190 }
191                 
192
193 void
194 refresh_screen()
195 {
196 #ifdef SIGWINCH
197         if( should_resize ) {
198                 resize_abook();
199                 return;
200         }
201 #endif
202         clear();
203         
204         refresh_statusline();
205         headerline(MAIN_HELPLINE);
206         list_headerline();
207
208         refresh_list();
209 }
210
211
212 void
213 statusline_msg(char *msg)
214 {
215         clear_statusline();
216         statusline_addstr(msg);
217         getch();
218 #ifdef DEBUG
219         fprintf(stderr, "statusline_msg(\"%s\")\n", msg);
220 #endif
221         clear_statusline();
222 }
223
224 void
225 statusline_addstr(char *str)
226 {
227         mvwaddstr(bottom, 1, 0, str);
228         refresh();
229         wrefresh(bottom);
230 }
231
232 /*
233  * function statusline_getnstr
234  *
235  * parameters:
236  *  (char *str)
237  *   if n >= 0 str is a pointer which points a place where to store
238  *   the string, else str is ingnored
239  *  (int n)
240  *   the maximum length of the string
241  *   If n < 0 function will allocate needed space for the string.
242  *   Value 0 is not allowed for n.
243  *  (int use_filesel)
244  *   if this value is nonzero the fileselector is enabled
245  *
246  *  returns (char *)
247  *   If n < 0 a pointer to a newly allocated string is returned.
248  *   If n > 0 a nonzero value is returned if user has typed a valid
249  *   string. If not NULL value is returned. Never really use the
250  *   _pointer_ if n > 0.
251  *
252  */
253
254 char *
255 statusline_getnstr(char *str, int n, int use_filesel)
256 {
257         char *buf;
258         int y, x;
259
260         getyx(bottom, y, x);
261         wmove(bottom, 1, x);
262         
263         buf = wenter_string(bottom, n,
264                         (use_filesel ? ESTR_USE_FILESEL:0) | ESTR_DONT_WRAP);
265
266         if(n < 0)
267                 return buf;
268         
269         if(buf == NULL)
270                 str[0] = 0;
271         else
272                 strncpy(str, buf, n);
273
274         str[n-1] = 0;
275
276         free(buf);
277
278         return buf;
279 }
280
281 void
282 refresh_statusline()
283 {
284         werase(bottom);
285
286         mvwhline(bottom, 0, 0, UI_HLINE_CHAR, COLS);
287         mvwhline(bottom, 2, 0, UI_HLINE_CHAR, COLS);
288
289         refresh();
290         wrefresh(bottom);
291 }
292         
293
294 char *
295 ask_filename(char *prompt, int flags)
296 {
297         char *buf = NULL;
298
299         clear_statusline();
300         
301         statusline_addstr(prompt);
302         buf = statusline_getnstr(NULL, -1, flags);
303
304         clear_statusline();
305
306         return buf;
307 }
308
309 void
310 clear_statusline()
311 {
312         wmove(bottom, 1, 0);
313         wclrtoeol(bottom);
314         wrefresh(bottom);
315         refresh();
316 }
317
318
319 /*
320  * help - need to rewrite
321  */
322
323
324 #include "help.h"
325
326 void
327 display_help(int help)
328 {
329         int i;
330         char **tbl;
331         WINDOW *helpw;
332
333         switch(help) {
334                 case HELP_MAIN:
335                         tbl = mainhelp;
336                         break;
337                 case HELP_EDITOR:
338                         tbl = editorhelp;
339                         break;
340                 default:return;
341         }
342
343         helpw = newwin(LINES - 5, COLS - 6, 2, 3);
344         erase();
345         headerline("help");
346         
347         for( i = 0; tbl[i] != NULL; i++) {
348                 waddstr(helpw, tbl[i]);
349                 if( ( !( (i+1) % (LINES-8) ) ) ||
350                         (tbl[i+1] == NULL) ) {
351                         refresh();
352                         wrefresh(helpw);
353                         refresh_statusline();
354                         statusline_msg("Press any key to continue...");
355                         wclear(helpw);
356                 }
357         }
358
359         clear_statusline();
360         delwin(helpw);
361 }
362
363
364 /*
365  * end of help
366  */
367
368 char *selected;
369 extern int curitem;
370
371 void
372 get_commands()
373 {
374         int ch;
375
376         for(;;) {
377                 can_resize = TRUE; /* it's safe to resize now */
378                 hide_cursor();
379                 if( should_resize )
380                         refresh_screen();
381                 ch = getch();
382                 show_cursor();
383                 can_resize = FALSE; /* it's not safe to resize anymore */
384                 switch( ch ) {
385                         case 'q': return;
386                         case '?':
387                                   display_help(HELP_MAIN);
388                                   refresh_screen();
389                                   break;
390                         case 'a': add_item();           break;
391                         case '\r': edit_item(-1);       break;
392                         case KEY_DC:
393                         case 'd':
394                         case 'r': ui_remove_items();    break;
395                         case 12: refresh_screen();      break;
396
397                         case 'k':
398                         case KEY_UP: scroll_up();       break;
399                         case 'j':
400                         case KEY_DOWN: scroll_down();   break;
401                         case 'K':
402                         case KEY_PPAGE: page_up();      break;
403                         case 'J':
404                         case KEY_NPAGE: page_down();    break;
405
406                         case 'H':
407                         case KEY_HOME: goto_home();     break;
408                         case 'E':
409                         case KEY_END: goto_end();       break;
410
411                         case 'w': save_database();
412                                   break;
413                         case 'l': ui_read_database();   break;
414                         case 'i': import_database();    break;
415                         case 'e': export_database();    break;
416                         case 'C': ui_clear_database();  break;
417
418                         case 'o': ui_open_datafile();   break;
419
420                         case 's': sort_database();      break;
421                         case 'S': sort_surname();       break;
422
423                         case '/': ui_find(0);           break;
424                         case '\\': ui_find(1);          break;
425
426                         case ' ': if(curitem >= 0) {
427                                    selected[curitem] = !selected[curitem];
428                                    ui_print_number_of_items();
429                                    refresh_list();
430                                   }
431                                 break;
432                         case '+': select_all();
433                                   refresh_list();
434                                 break;
435                         case '-': select_none();
436                                   refresh_list();
437                                 break;
438                         case '*': invert_selection();
439                                   refresh_list();
440                                  break;
441                         case 'A': move_curitem(MOVE_ITEM_UP);
442                                 break;
443                         case 'Z': move_curitem(MOVE_ITEM_DOWN);
444                                 break;
445
446                         case 'm': launch_mutt(); break;
447
448                         case 'p': ui_print_database(); break;
449
450                         case 'u': launch_lynx(); break;
451                 }
452         }
453 }
454
455
456 void
457 ui_remove_items()
458 {
459         if( items < 1 || curitem < 0 )
460                 return;
461
462         statusline_addstr("Remove selected item(s) (Y/n)");
463         switch( getch() ) {
464                 case '\r':
465                 case 'y':
466                 case 'Y': break;
467                 default:
468                           clear_statusline();
469                           return;
470         }
471
472         remove_selected_items();
473
474         clear_statusline();     
475         refresh_list();
476 }
477
478 void
479 ui_clear_database()
480 {
481
482         statusline_addstr("Clear WHOLE database (y/N)");
483         switch( getch() ) {
484                 case 'y':
485                 case 'Y': break;
486                 default:
487                         clear_statusline();
488                         return;
489         }
490
491         close_database();
492
493         refresh_screen();
494 }
495
496 void
497 ui_find(int next)
498 {
499         int item;
500         static char findstr[81];
501
502         if(next) {
503                 if( !*findstr )
504                         return;
505         } else {
506                 clear_statusline();
507                 statusline_addstr("/");
508                 statusline_getnstr(findstr, 67, 0);
509                 clear_statusline();
510         }
511
512         if( (item = find_item(findstr, next ? curitem+1 : curitem)) >= 0 ) {
513                 curitem = item;
514                 refresh_list();
515         }
516
517 }
518
519
520 void
521 ui_print_number_of_items()
522 {
523         char *str = mkstr("     " "|%3d/%3d", selected_items(), items);
524
525         mvaddstr(0, COLS-strlen(str), str);
526
527         free(str);
528 }
529
530 void
531 ui_read_database()
532 {
533         if(items > 0) {
534                 statusline_addstr("Your current data will be lost - Press 'y' to continue");
535                 switch( getch() ) {
536                         case 'y':
537                         case 'Y': break;
538                         default: clear_statusline();
539                                  return;
540                 }
541                 clear_statusline();
542         }
543
544         load_database(datafile);
545         refresh_list();
546 }
547
548
549 void
550 ui_print_database()
551 {
552         FILE *handle;
553         char *command = options_get_str("print_command");
554
555         statusline_addstr("Print addressbook? (y/N)");
556         switch( getch() ) {
557                 case 'y':
558                 case 'Y':
559                         break;
560                 default: clear_statusline(); return;
561         }
562         clear_statusline();
563
564         if( ! *command || (handle = popen(command, "w")) == NULL)
565                 return;
566
567         fexport("text", handle);
568         
569         pclose(handle);
570 }
571
572
573 void
574 ui_open_datafile()
575 {
576         char *filename;
577
578         filename = ask_filename("File to open: ", 1);
579
580         if( !filename ) {
581                 refresh_screen();
582                 return;
583         }
584
585         if( options_get_int("autosave") )
586                 save_database();
587         else {
588                 statusline_addstr("Save current database (y/N)");
589                 switch( getch() ) {
590                         case 'y':
591                         case 'Y':
592                                 save_database();
593                         default: break;
594                 }
595         }
596
597         close_database();
598
599         load_database(filename);
600
601         if( items == 0 ) {
602                 statusline_msg("Sorry, that specified file appears not to be a valid abook addressbook");
603                 load_database(datafile);
604         } else {
605                 free(datafile);
606                 datafile = strdup(filename);
607         }
608
609         refresh_screen();
610         free(filename);
611 }