]> git.deb.at Git - pkg/abook.git/blob - ui.c
launch_mutt() update
[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(selected_items() ?
469                                                   -1 : list_current_item());
470                                   refresh_screen();
471                                   break;
472
473                         case 'p': ui_print_database(); break;
474
475                         case 'u': launch_wwwbrowser(list_current_item());
476                                   refresh_screen();
477                                   break;
478                 }
479         }
480 }
481
482
483 void
484 ui_remove_items()
485 {
486         if(list_is_empty())
487                 return;
488
489         if(statusline_ask_boolean("Remove selected item(s)", TRUE))
490                 remove_selected_items();
491
492         clear_statusline();     
493         refresh_list();
494 }
495
496 void
497 ui_clear_database()
498 {
499         if(statusline_ask_boolean("Clear WHOLE database", FALSE)) {
500                 close_database();
501                 refresh_list();
502         }
503 }
504
505 void
506 ui_find(int next)
507 {
508         int item;
509         static char findstr[81];
510         int search_fields[] = {NAME, EMAIL, NICK, -1};
511
512         if(next) {
513                 if( !*findstr )
514                         return;
515         } else {
516                 clear_statusline();
517                 statusline_addstr("/");
518                 statusline_getnstr(findstr, 67, 0);
519                 clear_statusline();
520         }
521
522         if( (item = find_item(findstr, next ? curitem+1 : curitem,
523                                         search_fields )) >= 0 ) {
524                 curitem = item;
525                 refresh_list();
526         }
527
528 }
529
530
531 void
532 ui_print_number_of_items()
533 {
534         char *str = mkstr("     " "|%3d/%3d", selected_items(), items);
535
536         mvaddstr(0, COLS-strlen(str), str);
537
538         free(str);
539 }
540
541 void
542 ui_read_database()
543 {
544         if(items > 0)
545                 if(!statusline_ask_boolean("Your current data will be lost - "
546                                 "Press 'y' to continue", FALSE))
547                         return;
548
549         load_database(datafile);
550         refresh_list();
551 }
552
553
554 void
555 ui_print_database()
556 {
557         FILE *handle;
558         char *command = options_get_str("print_command");
559         int mode;
560
561         if( list_is_empty() )
562                 return;
563
564         statusline_addstr("Print All/Selected/Cancel (a/s/C)?");
565
566         switch( tolower(getch()) ) {
567                 case 'a':
568                         mode = ENUM_ALL;
569                         break;
570                 case 's':
571                         if( !selected_items() ) {
572                                 statusline_msg("No selected items");
573                                 return;
574                         }
575                         mode = ENUM_SELECTED;
576                         break;
577                 default:
578                         clear_statusline();
579                         return;
580         }
581
582         clear_statusline();
583
584         if( ! *command || (handle = popen(command, "w")) == NULL)
585                 return;
586
587         fexport("text", handle, mode);
588         
589         pclose(handle);
590 }
591
592
593 void
594 ui_open_datafile()
595 {
596         char *filename;
597
598         filename = ask_filename("File to open: ", 1);
599
600         if( !filename ) {
601                 refresh_screen();
602                 return;
603         }
604
605         if( options_get_int("autosave") )
606                 save_database();
607         else if(statusline_ask_boolean("Save current database", FALSE))
608                 save_database();
609
610         close_database();
611
612         load_database(filename);
613
614         if( items == 0 ) {
615                 statusline_msg("Sorry, that specified file appears not to be a valid abook addressbook");
616                 load_database(datafile);
617         } else {
618                 free(datafile);
619                 datafile = strdup(filename);
620         }
621
622         refresh_screen();
623         free(filename);
624 }