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