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