]> git.deb.at Git - pkg/abook.git/blob - edit.c
c4f17afbdc41336b202336e3968a6aeaae22319a
[pkg/abook.git] / edit.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <assert.h>
13 #include "abook_curses.h"
14 #include "ui.h"
15 #include "abook.h"
16 #include "database.h"
17 #include "gettext.h"
18 #include "list.h"
19 #include "edit.h"
20 #include "misc.h"
21 #include "xmalloc.h"
22 #ifdef HAVE_CONFIG_H
23 #       include "config.h"
24 #endif
25
26 /*
27  * some extern variables
28  */
29
30 extern struct abook_field abook_fields[];
31
32 extern list_item *database;
33 extern int curitem;
34 extern int items;
35
36 WINDOW *editw;
37
38 static void
39 editor_tab(const int tab)
40 {
41         int i, j;
42         int x_pos = 2; /* current x pos */
43         static char *tab_names[] = {
44                 N_("CONTACT"),
45                 N_("ADDRESS"),
46                 N_(" PHONE "),
47                 N_(" OTHER "),
48                 N_("CUSTOM ")
49         };
50
51         mvwhline(editw, TABLINE + 1, 0, UI_HLINE_CHAR, EDITW_COLS);
52
53         for(i = 0; i < TABS; i++) {
54                 int width = strwidth(gettext(tab_names[i])) + 5;
55
56                 if(x_pos + width + 1 > EDITW_COLS) {
57                         statusline_msg(_("Tab name too wide for screen"));
58                         break;
59                 }
60
61                 mvwaddch(editw,  TABLINE + 1, x_pos,  UI_TEE_CHAR);
62                 mvwaddch(editw,  TABLINE + 1, x_pos + width - 2, UI_TEE_CHAR);
63
64                 mvwaddch(editw,  TABLINE, x_pos,  UI_ULCORNER_CHAR);
65                 mvwaddch(editw,  TABLINE, x_pos + 1,  UI_LBOXLINE_CHAR);
66                 mvwaddstr(editw, TABLINE, x_pos + 2,  gettext(tab_names[i]));
67                 mvwaddch(editw,  TABLINE, x_pos + width - 3, UI_RBOXLINE_CHAR);
68                 mvwaddch(editw,  TABLINE, x_pos + width - 2, UI_URCORNER_CHAR);
69
70                 if(i == tab) {
71                         mvwaddch(editw,  TABLINE + 1, x_pos, UI_LRCORNER_CHAR);
72                         for(j = 0; j < width - 3; j++)
73                                 mvwaddstr(editw,
74                                         TABLINE + 1, x_pos + j + 1, " ");
75                         mvwaddch(editw,  TABLINE + 1, x_pos + width - 2,
76                                 UI_LLCORNER_CHAR);
77                 }
78                 x_pos += width;
79         }
80 }
81
82 void
83 get_first_email(char *str, int item)
84 {
85         char *tmp;
86
87         if(database[item][EMAIL] == NULL) {
88                 *str = 0;
89                 return;
90         }
91
92         strncpy(str, database[item][EMAIL], MAX_EMAIL_LEN);
93         if( (tmp = strchr(str, ',')) )
94                 *tmp = 0;
95         else
96                 str[MAX_EMAIL_LEN-1] = 0;
97 }
98
99 static void
100 roll_emails(int item)
101 {
102         char tmp[MAX_EMAILSTR_LEN];
103         char *p;
104
105         strcpy(tmp, database[item][EMAIL]);
106
107         if( !(p = strchr(tmp, ',')) )
108                 return;
109         else
110                 *p = 0;
111
112         strcpy(database[item][EMAIL], p+1);
113         strcat(database[item][EMAIL], ",");
114         strcat(database[item][EMAIL], tmp);
115 }
116
117 static void
118 init_editor()
119 {
120         clear();
121         editw = newwin(EDITW_LINES, EDITW_COLS, EDITW_TOP, EDITW_X);
122
123         refresh_statusline();
124 }
125
126 enum {
127         BACKUP_ITEM,
128         RESTORE_ITEM,
129         CLEAR_UNDO
130 };
131
132 static void
133 edit_undo(int item, int mode)
134 {
135         int i;
136         static list_item *backup = NULL;
137
138         switch(mode) {
139                 case CLEAR_UNDO:
140                         if(backup) {
141                                 free_list_item(backup[0]);
142                                 xfree(backup);
143                         }
144                         break;
145                 case BACKUP_ITEM:
146                         if(backup) {
147                                 free_list_item(backup[0]);
148                                 xfree(backup);
149                         }
150                         backup = xmalloc(sizeof(list_item));
151                         for(i = 0; i < ITEM_FIELDS; i++)
152                                 if(database[item][i] == NULL)
153                                         backup[0][i] = NULL;
154                                 else
155                                         backup[0][i] =
156                                                 xstrdup(database[item][i]);
157                         break;
158                 case RESTORE_ITEM:
159                         if(backup) {
160                                 free_list_item(database[item]);
161                                 itemcpy(database[item], backup[0]);
162                                 xfree(backup);
163                         }
164                         break;
165                 default:
166                         assert(0);
167         }
168 }
169
170
171 static void
172 close_editor()
173 {
174         edit_undo(-1, CLEAR_UNDO);
175         delwin(editw);
176         refresh_screen();
177 }
178
179 static void
180 print_editor_header(int item)
181 {
182         char *header;
183         char email[MAX_EMAIL_LEN];
184
185         if((header = xmalloc(EDITW_COLS)) == NULL)
186                 return;
187
188         get_first_email(email, item);
189
190         if(*database[item][EMAIL])
191                 snprintf(header, EDITW_COLS, "%s <%s>",
192                                 database[item][NAME],
193                                 email);
194         else
195                 snprintf(header, EDITW_COLS, "%s", database[item][NAME]);
196
197         mvwaddstr(editw, 0, (EDITW_COLS - strwidth(header)) / 2,
198                         header);
199
200         free(header);
201 }
202
203 static void
204 editor_print_data(int tab, int item)
205 {
206         int i, j;
207         int y, x;
208
209         for(i = 0, j = 1; i < ITEM_FIELDS; i++) {
210                 if(abook_fields[i].tab != tab)
211                         continue;
212
213                 if(i == EMAIL) { /* special field */
214                         int k;
215                         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
216                         split_emailstr(item, emails);
217                         getyx(editw, y, x);
218                         mvwaddstr(editw, y+1, FIELDS_START_X,
219                                         _("E-mail addresses:"));
220                         for(k = 0; k < MAX_EMAILS; k++) {
221                                 getyx(editw, y, x);
222                                 mvwprintw(editw, y+1, FIELDS_START_X,
223                                 "%c -", '2' + k);
224                                 mvwprintw(editw, y +1, TAB_COLON_POS,
225                                                 ": %s", emails[k]);
226                         }
227                         continue;
228                 }
229
230                 if(j > 1) {
231                         getyx(editw, y, x);
232                         y++;
233                 } else
234                         y = FIELDS_START_Y;
235
236                 mvwprintw(editw, y, FIELDS_START_X, "%d - %s",
237                                 j,
238                                 gettext(abook_fields[i].name));
239                 mvwaddch(editw, y, TAB_COLON_POS, ':');
240                 mvwaddstr(editw, y, TAB_COLON_POS + 2,
241                                 safe_str(database[item][i]));
242
243                 j++;
244         }
245 }
246
247 /*
248  * function: change_field
249  *
250  * parameters:
251  *  (char *msg)
252  *   message to display as a prompt
253  *  (char **field)
254  *   a pointer to a pointer which will point a new string. if the latter
255  *   pointer != NULL it will be freed (if user doesn't cancel)
256  *
257  * returns (int)
258  *  a nonzero value if user has cancelled and zero if user has typed a
259  *  valid string
260  */
261
262 static int
263 change_field(char *msg, char **field)
264 {
265         int max_len = MAX_FIELD_LEN;
266         char *old;
267         int ret = 0;
268
269         if(!strncmp("E-mail", msg, 6))
270                 max_len = MAX_EMAIL_LEN;
271
272         old = *field;
273
274         *field = ui_readline(msg, old, max_len - 1, 0);
275
276         if(*field) {
277                 xfree(old);
278                 if(!**field)
279                         xfree(*field);
280         } else {
281                 *field = old;
282                 ret = 1;
283         }
284
285         clear_statusline();
286         refresh_statusline();
287
288         return ret;
289 }
290
291 static void
292 change_name_field(char **field)
293 {
294         char *tmp;
295
296         tmp = xstrdup(*field);
297         change_field("Name: ", field);
298
299         if(*field == NULL || ! **field) {
300                 xfree(*field);
301                 *field = xstrdup(tmp);
302         }
303
304         xfree(tmp);
305 }
306
307 static void
308 fix_email_str(char *str)
309 {
310         for(; *str; str++)
311                 *str = *str == ',' ? '_' : *str;
312 }
313
314 static void
315 edit_emails(char c, int item)
316 {
317         char *field;
318         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
319         char tmp[MAX_EMAILSTR_LEN] = "";
320         int i, len;
321         int email_num = c - '2';
322
323         split_emailstr(item, emails);
324         field = xstrdup(emails[email_num]);
325
326         if(change_field("E-mail: ", &field))
327                 return; /* user cancelled ( C-g ) */
328
329         if(field) {
330                 strncpy(emails[email_num], field, MAX_EMAIL_LEN);
331                 fix_email_str(emails[email_num]);
332         } else
333                 *emails[email_num] = 0;
334
335         xfree(database[item][EMAIL]);
336
337         for(i = 0; i < MAX_EMAILS; i++) {
338                 if( *emails[i] ) {
339                         strcat(tmp, emails[i]);
340                         strcat(tmp, ",");
341                 }
342         }
343
344         len = strlen(tmp);
345         if(tmp[len -1] == ',')
346                 tmp[len-1] =0;
347
348         database[item][EMAIL] = xstrdup(tmp);
349 }
350
351 static int
352 edit_field(int tab, char c, int item)
353 {
354         int i, j;
355         int n = c - '1' + 1;
356         char *str;
357
358         if(n < 1 || n > MAX_TAB_FIELDS)
359                 return 0;
360
361         edit_undo(item, BACKUP_ITEM);
362
363         if(tab == TAB_CONTACT) {
364                 switch(c) {
365                         case '1': change_name_field(&database[item][NAME]);
366                                   break;
367                         case '2':
368                         case '3':
369                         case '4':
370                         case '5': edit_emails(c, item); break;
371                         default: return 0;
372                 }
373                 return 1;
374         }
375
376         for(i = 0, j = 0; i< ITEM_FIELDS; i++) {
377                 if(abook_fields[i].tab == tab)
378                         j++;
379                 if(j==n)
380                         break;
381         }
382
383         if(j != n)
384                 return 0;
385
386         str = strdup_printf("%s: ", gettext(abook_fields[i].name));
387         change_field(str, &database[item][i]);
388
389         free(str);
390
391         return 1;
392 }
393
394 static int
395 edit_loop(int item)
396 {
397         static int tab = 0; /* first tab */
398         int c;
399
400         werase(editw);
401         headerline(gettext(EDITOR_HELPLINE));
402         refresh_statusline();
403         print_editor_header(item);
404         editor_tab(tab);
405         editor_print_data(tab, item);
406         wmove(editw, EDITW_LINES - 1, EDITW_COLS - 1);
407
408         refresh();
409         wrefresh(editw);
410
411         switch((c = getch())) {
412                 case 'c': tab = TAB_CONTACT; break;
413                 case 'a': tab = TAB_ADDRESS; break;
414                 case 'p': tab = TAB_PHONE; break;
415                 case 'o': tab = TAB_OTHER; break;
416                 case 'C': tab = TAB_CUSTOM; break;
417                 case 'h':
418                 case KEY_LEFT: tab = tab == 0 ? MAX_TAB : tab - 1;
419                                break;
420                 case 'l':
421                 case KEY_RIGHT: tab = tab == MAX_TAB ? 0 : tab + 1;
422                                 break;
423                 case KEY_UP:
424                 case '<':
425                 case 'k': if(is_valid_item(item-1)) item--; break;
426                 case KEY_DOWN:
427                 case '>':
428                 case 'j': if(is_valid_item(item + 1)) item++; break;
429                 case 'r': roll_emails(item); break;
430                 case '?': display_help(HELP_EDITOR); break;
431                 case 'u': edit_undo(item, RESTORE_ITEM); break;
432                 case 'm': launch_mutt(item); clearok(stdscr, 1); break;
433                 case 'v': launch_wwwbrowser(item); clearok(stdscr, 1); break;
434                 case 12 : clearok(stdscr, 1); break; /* ^L (refresh screen) */
435                 default:  return edit_field(tab, c, item) ? item : -1;
436         }
437
438         return item;
439 }
440
441 void
442 edit_item(int item)
443 {
444         if( item < 0 ) {
445                 if( curitem < 0 )
446                         return;
447                 else
448                         item = curitem;
449         }
450
451         init_editor();
452
453         while((item = edit_loop(item)) >= 0)
454                 curitem = item; /* hmm, this is not very clean way to go */
455
456         close_editor();
457 }
458
459 void
460 add_item()
461 {
462         char *field = NULL;
463         list_item item;
464
465         change_field("Name: ", &field);
466
467         if( field == NULL )
468                 return;
469
470         memset(item, 0, sizeof(item));
471
472         item[NAME] = field;
473
474         add_item2database(item);
475
476         curitem = LAST_ITEM;
477
478         edit_item(LAST_ITEM);
479 }
480