Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / blist.c
1 /*******************************************************************************
2 **
3 **  blist.c
4 **
5 **  $TOG: blist.c /main/5 1999/02/08 17:02:59 mgreess $
6 **
7 **  RESTRICTED CONFIDENTIAL INFORMATION:
8 **
9 **  The information in this document is subject to special
10 **  restrictions in a confidential disclosure agreement between
11 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
12 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
13 **  Sun's specific written approval.  This document and all copies
14 **  and derivative works thereof must be returned or destroyed at
15 **  Sun's request.
16 **
17 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
18 **
19 *******************************************************************************/
20
21 /*                                                                      *
22  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
23  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
24  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
25  * (c) Copyright 1993, 1994 Novell, Inc.                                *
26  */
27
28 #ifndef lint
29 static  char sccsid[] = "@(#)blist.c 1.66 95/03/28 Copyr 1994 Sun Microsystems, Inc.";
30 #endif
31
32 #include <EUSCompat.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/param.h>
36 #include <Xm/Xm.h>
37 #include <Xm/Form.h>
38 #include <Xm/Label.h>
39 #include <Xm/LabelG.h>
40 #include <Xm/List.h>
41 #include <Xm/DialogS.h>
42 #include <Xm/PushB.h>
43 #include <Xm/Text.h>
44 #include <Xm/TextF.h>
45 #include <Xm/RowColumn.h>
46 #include <Xm/SeparatoG.h>
47 #include "browser.h"
48 #include "calendar.h"
49 #include "util.h"
50 #include "misc.h"
51 #include "timeops.h"
52 #include "blist.h"
53 #include "props.h"
54 #include "help.h"
55
56
57 static void
58 bl_pending_change(Widget w, XtPointer data, XtPointer cbs) {
59         Calendar *c = (Calendar *) data;
60         Browselist      *bl = (Browselist *)c->browselist;
61
62         if (bl->bl_pending_message_up == False) {
63                 /* NL_COMMENT
64                    Attention Translator:
65
66                    Message 841 is used in the Menu Editor's footer.  The
67                    Menu Editor is accessed through the browse menu.  The 
68                    message is displayed when something is typed into the User
69                    Name field in the editor.  If the translated footer message 
70                    is too long it causes the menu editor to grow horizontally
71                    which we do not want.  If you notice that the translated
72                    string causes the editor to grow horizontally please
73                    insert a newline (\n) character somewhere in the middle
74                    of the string so the footer will use two lines and the
75                    editor will grow vertically.
76                 */
77                 set_message(bl->message, catgets(c->DT_catd, 1, 841, "Click on \"Add Name\" to add a name, \"Apply\" to commit changes."));
78                 bl->bl_pending_message_up = True;
79                 XtSetSensitive(bl->add_button, True);
80         }
81 }
82
83 static void
84 bl_clear_pending_change(Browselist *bl) {
85
86         if (bl->bl_pending_message_up == True) {
87                 set_message(bl->message, " ");
88                 bl->bl_pending_message_up = False;
89                 XtSetSensitive(bl->add_button, False);
90         }
91 }
92
93 static void
94 bl_list_is_changed(Browselist *bl) {
95
96         if (bl->bl_list_changed == False) {
97                 bl->bl_list_changed = True;
98                 XtSetSensitive(bl->ok_button, True);
99                 XtSetSensitive(bl->apply_button, True);
100                 XtSetSensitive(bl->reset_button, True);
101                 XtVaSetValues(bl->form, XmNdefaultButton, bl->apply_button, NULL);
102         }
103 }
104
105 static void
106 bl_list_not_changed(Browselist *bl) {
107
108         bl->bl_list_changed = False;
109         XtSetSensitive(bl->ok_button, False);
110         XtSetSensitive(bl->apply_button, False);
111         XtSetSensitive(bl->reset_button, False);
112         XtVaSetValues(bl->form, XmNdefaultButton, bl->cancel_button, NULL);
113 }
114
115 static void
116 bl_list_selection_cb(Widget w, XtPointer data, XtPointer cbs) {
117         Calendar *c = (Calendar *) data;
118         Browselist      *bl = (Browselist *)c->browselist;
119         int             *pos_list, pos_cnt;
120
121         XmListGetSelectedPos(bl->browse_list, &pos_list, &pos_cnt);
122         if (pos_cnt <= 0) 
123                 XtSetSensitive(bl->remove_button, False);
124         else
125                 XtSetSensitive(bl->remove_button, True);
126 }
127
128 /*
129  * Remove the name from the UI and from the list if the calendar handle is NULL.
130  * If the calendar handle is not null, tag it as deleted and it will be taken
131  * care of later.
132  */
133 static void
134 blist_removenames(Widget widget, XtPointer client_data, XtPointer call_data) {
135         int             i, idx, valid_cnt, *pos_list, pos_cnt;
136         Calendar        *c = (Calendar *)client_data;
137         BlistData       *bd = NULL;
138         Browselist      *bl = (Browselist *)c->browselist;
139         int             rejected_name = 0;
140
141         set_message(bl->message, " ");
142         XmListGetSelectedPos(bl->browse_list, &pos_list, &pos_cnt);
143         if (pos_cnt <= 0) {
144                 set_message(bl->message, catgets(calendar->DT_catd, 1, 17,
145                                               "Select a name to remove"));
146                 return;
147         }
148
149         for (i = 0; i < pos_cnt; i++) {
150                 if (pos_list[i] == 1) {
151                         set_message(bl->message, catgets(calendar->DT_catd, 1,
152                                 16, "You may not remove the default calendar"));
153                         rejected_name++;
154                         continue;
155                 }
156
157                 XmListDeletePos(bl->browse_list, pos_list[i] - i + rejected_name);
158                 bd = (BlistData *)CmDataListGetData(bl->blist_data, pos_list[i]);
159
160                 if (bd)
161                 {
162                         bd->tag = BLIST_DELETE;
163                 }
164         }
165         blist_clean(bl, False);
166         bl_list_is_changed(bl);
167 }
168
169 /*
170  * Append the new name to the list and set the necessary tags.  Note this only
171  * adds the name to the linked list - not to the UI.  Also, it won't add a
172  * duplicate name.
173  */
174 static int
175 blist_name_append(Calendar *c, char *name, BlistTag t) {
176         int             i = 1;
177         Boolean         marked = False;
178         int             location = 2;
179         BlistData       *bd;
180         Browselist      *bl = (Browselist *)c->browselist;
181         char            *defname;
182  
183
184         /* This while loop is doing double duty here.  The primary 
185            purpose of the list is to find out if the name we're 
186            inserting is already in the list.  While looping thru, 
187            the secondary purpose is to find the lexicographical 
188            position of the name relative to the current set of entries.  
189            The business about marked and location is related to that 
190            second purpose. */
191
192         while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i)) &&
193                strcmp(bd->name, name) != 0)
194         {
195                 if ((marked == False) && (strcoll(name, bd->name) < 0) && 
196                     (i != 1)) {
197                         location = i;
198                         marked = True;
199                 }
200                 ++i;
201         }
202
203         if (bd) {
204                 /* Since the user may have hit the reset button, any items
205                  * that had been marked for deletion need to be made active.
206                  */
207                 if (bd->tag == BLIST_DELETE)
208                         bd->tag = BLIST_ACTIVE;
209
210                 return -1;
211         }
212         
213         /* 2 special cases here.  If the name is that of the calendar 
214            owner, it should always be at the head of the list.  If the 
215            name wasn't maked against any of the people on the list, 
216            then it should be inserted at the end. */
217
218         defname = get_user_calendar();
219         if (strcmp(defname, name) == 0) {
220                 location = 1;
221         } else if (marked == False) {
222                 location = i;
223         }
224         free(defname);
225  
226         bd = (BlistData *)ckalloc(sizeof(BlistData));
227         bd->name = cm_strdup(name);
228         bd->tag = t;
229         bd->cal_handle = NULL;
230         CmDataListAdd(bl->blist_data, (void *)bd, location);
231  
232         return location;
233
234 }
235
236 /*
237  * Callback for the add name button.  This simply calls the blist_name_append
238  * function and adds the name to the UI.
239  */
240 static void
241 blist_addname(Widget widget, XtPointer client_data, XtPointer cbs) {
242         char            *new_name, *end_ptr, buf[MAXNAMELEN];
243         XEvent          *e = ((XmAnyCallbackStruct *)cbs)->event;
244         XmString        xmstr;
245         Calendar        *c = (Calendar *)client_data;
246         Browselist      *bl = (Browselist *)c->browselist;
247         int             insert_location;
248
249
250         XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_NONE, NULL);
251         bl_clear_pending_change(bl);
252         bl_list_is_changed(bl);
253         set_message(bl->message, " ");
254         new_name = XmTextFieldGetString(bl->username);
255
256         /* crush out leading white space for the name 
257            comparison/insert process */
258         
259         while ((*new_name == ' ') || (*new_name == '\t'))
260                 new_name++;
261
262         /* compress off trailing whitespace */
263
264         end_ptr = new_name;
265         while (*end_ptr)
266                 end_ptr++;
267         while ((end_ptr > new_name) && 
268                ((*(end_ptr - 1) == ' ') || (*(end_ptr - 1) == '\t')))
269                 end_ptr--;
270
271         *end_ptr = NULL;
272
273
274         if (blank_buf(new_name)) {
275                 set_message(bl->message, catgets(c->DT_catd, 1, 603,
276                         "Type a name to add in the User Name field"));
277                 return;
278         }
279
280         if (embedded_blank(new_name)) {
281                 set_message(bl->message, catgets(c->DT_catd, 1, 684,
282                         "User Names may not have embedded blanks or tabs"));
283                 return;
284         }
285
286
287         if ((insert_location = blist_name_append(c, new_name, BLIST_INSERT)) != -1) {
288                 xmstr = XmStringCreateLocalized(new_name);
289                 XmListAddItem(bl->browse_list, xmstr, insert_location);
290                 XmStringFree(xmstr);
291                 cm_select_text(bl->username, e->xbutton.time);
292         } else {
293                 sprintf(buf, "%s %s", new_name,
294                         catgets(c->DT_catd, 1, 604, "is already in the list"));
295                 set_message(bl->message, buf);
296         }
297         XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_ANY, NULL);
298 }
299
300 /*
301  * This sends the new list of names to the properties database.  Note it ignores
302  * items that have been tagged for deletion.
303  */
304 static void
305 blist_write_list(Browselist *bl, Props *p) {
306         int             i, len = 0;
307         char            *buf;
308         BlistData       *bd;
309
310         /*
311          * First pass, count the number of bytes we're going to need
312          */
313         for (i = 1; i <= bl->blist_data->count; i++) {
314                 bd = (BlistData *)CmDataListGetData(bl->blist_data, i);
315                 if (bd && bd->name && bd->tag != BLIST_DELETE)
316                         len += cm_strlen(bd->name) + 2; /* one for spacing */
317         }
318         if (len <= 0)
319                 return;
320
321         /*
322          * We have names, so build the string, making sure to exclude items
323          * tagged for delete.
324          */
325         buf = (char *)ckalloc(len);
326         memset(buf, '\0', len);
327         for (i = 1; i <= bl->blist_data->count; i++) {
328                 bd = (BlistData *)CmDataListGetData(bl->blist_data, i);
329                 if (bd && bd->name && bd->tag != BLIST_DELETE) {
330                         cm_strcat(buf, bd->name);
331                         cm_strcat(buf, " ");
332                         bd->tag = BLIST_ACTIVE;
333                 }
334         }
335         set_char_prop(p, CP_DAYCALLIST, buf);
336         save_props(p);
337         free(buf);
338 }
339
340 /*
341  * Callback for the OK button - will write the list to the properties
342  * database, will update the browse menu on the main menu, and will update the
343  * menu on the multi browser if it's up.
344  */
345 static void
346 blist_ok(Widget widget, XtPointer client_data, XtPointer call_data) {
347         Calendar        *c = (Calendar *)client_data;
348         Browselist      *bl = (Browselist *)c->browselist;
349         Browser         *b = (Browser *)c->browser;
350         Props           *p = (Props *)c->properties;
351
352         bl_clear_pending_change(bl);
353         bl_list_not_changed(bl);
354         set_message(bl->message, " ");
355         blist_write_list(bl, p);
356
357         XtVaSetValues(c->browse_button, XmNsubMenuId, NULL, NULL);
358         update_browse_menu_names(c);
359         XtVaSetValues(c->browse_button, XmNsubMenuId, c->browse_menu, NULL);
360         if (b && b->frame)
361                 browser_reset_list(c);
362
363         XtPopdown(bl->frame);
364 }
365
366 /*
367  * Callback for the apply button - will write the list to the properties
368  * database, will update the browse menu on the main menu, and will update the
369  * menu on the multi browser if it's up.
370  */
371 static void
372 blist_apply(Widget widget, XtPointer client_data, XtPointer call_data) {
373         Calendar        *c = (Calendar *)client_data;
374         Browselist      *bl = (Browselist *)c->browselist;
375         Browser         *b = (Browser *)c->browser;
376         Props           *p = (Props *)c->properties;
377
378         bl_clear_pending_change(bl);
379         bl_list_not_changed(bl);
380         set_message(bl->message, " ");
381         blist_write_list(bl, p);
382
383         XtVaSetValues(c->browse_button, XmNsubMenuId, NULL, NULL);
384         update_browse_menu_names(c);
385         XtVaSetValues(c->browse_button, XmNsubMenuId, c->browse_menu, NULL);
386         if (b && b->frame)
387                 browser_reset_list(c);
388 }
389
390 static void
391 blist_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data) {
392         Calendar        *c = (Calendar *)client_data;
393         Browselist      *bl = (Browselist *)c->browselist;
394
395         blist_reset(c);
396
397         XtPopdown(bl->frame);
398 }
399
400 static void
401 blist_reset_cb(Widget widget, XtPointer client_data, XtPointer call_data) {
402         Calendar        *c = (Calendar *)client_data;
403         Browselist      *bl = (Browselist *)c->browselist;
404
405         blist_reset(c);
406 }
407
408 extern void
409 blist_init_names(Calendar *c) {
410         char            *name, *namelist;
411         Props           *p = (Props*)c->properties;
412         Browselist      *bl = (Browselist *)c->browselist;
413  
414         if (!bl->blist_data)
415                 bl->blist_data = CmDataListCreate();
416
417         /*
418          * Make sure the default calendar is in list
419          */
420         name = get_user_calendar();
421         blist_name_append(c, name, BLIST_ACTIVE);
422         free(name);
423
424         /*
425          * Make sure user's calendar is in list
426          */
427         blist_name_append(c, c->calname, BLIST_ACTIVE);
428
429         /* make sure the intiial view name is in the list. */
430
431         blist_name_append(c, get_char_prop(p, CP_DEFAULTCAL), BLIST_ACTIVE);
432
433         namelist = cm_strdup(get_char_prop(p, CP_DAYCALLIST));
434         if (namelist == NULL || *namelist == NULL )
435                 return;
436
437         name = strtok(namelist, " ");
438         while (name) {
439                 blist_name_append(c, name, BLIST_ACTIVE);
440                 name = strtok(NULL, " ");
441         }
442         free(namelist);
443 }
444
445 extern void
446 blist_init_ui(Calendar *c) {
447         int             i;
448         XmString        xmstr;
449         BlistData       *bd;
450         Browselist      *bl = (Browselist *)c->browselist;
451
452         XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_NONE, NULL);
453         XmListDeleteAllItems(bl->browse_list);
454         for (i = 1; i <= bl->blist_data->count; i++) {
455                 bd = (BlistData *)CmDataListGetData(bl->blist_data, i);
456                 if (bd && bd->name && bd->tag != BLIST_DELETE) {
457                         xmstr = XmStringCreateLocalized(bd->name);
458                         if (!XmListItemExists(bl->browse_list, xmstr))
459                                 XmListAddItem(bl->browse_list, xmstr, 0);
460                         XmStringFree(xmstr);
461                 }
462         }
463         XmTextFieldSetString(bl->username, "");
464         XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_ANY, NULL);
465 }
466
467 extern void
468 blist_clean(Browselist *bl, Boolean clean_all) {
469         int             i, left_cnt = 1, cnt;
470         BlistData       *bd;
471
472         if (NULL == bl->blist_data) return;
473
474         cnt = bl->blist_data->count;
475         for (i = 1; i <= cnt; i++) {
476                 bd = (BlistData *)CmDataListGetData(bl->blist_data, left_cnt);
477                 if (bd && bd->cal_handle == NULL &&
478                     (clean_all || bd->tag != BLIST_ACTIVE)) {
479                         if (bd->name)
480                                 free(bd->name);
481                         CmDataListDeletePos(bl->blist_data, left_cnt, True);
482                 } else
483                         ++left_cnt;
484         }
485 }
486
487 extern void
488 blist_reset(Calendar *c) {
489         Browselist      *bl = (Browselist *)c->browselist;
490
491         blist_clean(bl, True);
492         blist_init_names(c);
493         blist_init_ui(c);
494         bl_clear_pending_change(bl);
495         bl_list_not_changed(bl);
496         XtSetSensitive(bl->remove_button, False);
497 }
498
499 static void
500 blist_quit_handler(Widget w, XtPointer cdata, XtPointer data) {
501         Browselist      *bl = (Browselist *)cdata;
502
503         XtPopdown(w);
504 }
505
506 extern void
507 make_browselist(Calendar *c)
508 {
509         int             ac;
510         Arg             args[15];
511         XmString        label_str;
512         Widget          separator,
513                         button_form;
514         Browselist      *bl = (Browselist *)c->browselist;
515         Dimension       label_width;
516         char            *title;
517
518         if (!bl)
519                 return;
520
521         title = XtNewString(catgets(c->DT_catd, 1, 963, 
522                                     "Calendar : Menu Editor"));
523         bl->frame = XtVaCreatePopupShell("menu_editor_frame",
524                 xmDialogShellWidgetClass, c->frame,
525                 XmNdeleteResponse,      XmDO_NOTHING,
526                 XmNtitle, title,
527                 XmNallowShellResize,    True,
528                 XmNmappedWhenManaged,   False,
529                 NULL);
530         setup_quit_handler(bl->frame, blist_quit_handler, (caddr_t)bl);
531         XtFree(title);
532
533         bl->form = XtVaCreateWidget("menu_editor_form",
534                 xmFormWidgetClass, bl->frame,
535                 XmNautoUnmanage,        False,
536                 XmNfractionBase,        5,
537                 NULL);
538
539         label_str = XmStringCreateLocalized(
540                                 catgets(c->DT_catd, 1, 410, "User Name:"));
541         bl->username_label = XtVaCreateWidget("name_label",
542                 xmLabelGadgetClass, bl->form,
543                 XmNlabelString,         label_str,
544                 NULL);
545         XmStringFree(label_str);
546
547         ac = 0;
548         XtSetArg(args[ac], XmNorientation,      XmVERTICAL);    ++ac;
549         XtSetArg(args[ac], XmNpacking,          XmPACK_COLUMN); ++ac;
550         XtSetArg(args[ac], XmNtopAttachment,    XmATTACH_FORM); ++ac;
551         XtSetArg(args[ac], XmNtopOffset,        6);             ++ac;
552         XtSetArg(args[ac], XmNrightAttachment,  XmATTACH_FORM); ++ac;
553         XtSetArg(args[ac], XmNrightOffset,      5);             ++ac;
554         bl->edit_rc_mgr = XmCreateRowColumn(bl->form, "edit_rc_mgr", args, ac);
555
556         label_str = XmStringCreateLocalized(
557                                 catgets(c->DT_catd, 1, 686, "Add Name"));
558         bl->add_button = XtVaCreateWidget("add_button",
559                 xmPushButtonWidgetClass, bl->edit_rc_mgr,
560                 XmNlabelString,         label_str,
561                 XmNnavigationType,      XmTAB_GROUP,
562                 NULL);
563         XmStringFree(label_str);
564         XtAddCallback(bl->add_button, XmNactivateCallback,
565                                 blist_addname, (XtPointer)c);
566
567         label_str = XmStringCreateLocalized(
568                                 catgets(c->DT_catd, 1, 687, "Remove Name"));
569         bl->remove_button = XtVaCreateWidget("remove_button",
570                 xmPushButtonWidgetClass, bl->edit_rc_mgr,
571                 XmNlabelString,         label_str,
572                 XmNnavigationType,      XmTAB_GROUP,
573                 NULL);
574         XmStringFree(label_str);
575         XtAddCallback(bl->remove_button, XmNactivateCallback, 
576                                 blist_removenames, (XtPointer)c);
577         ManageChildren(bl->edit_rc_mgr);
578
579         XtVaGetValues(bl->username_label, XmNwidth, &label_width, NULL);
580
581         bl->username = XtVaCreateWidget("username",
582                 xmTextFieldWidgetClass, bl->form,
583                 XmNleftAttachment,      XmATTACH_FORM,
584                 XmNleftOffset,          label_width + 15,
585                 XmNrightAttachment,     XmATTACH_WIDGET,
586                 XmNrightWidget,         bl->edit_rc_mgr,
587                 XmNrightOffset,         5,
588                 XmNtopAttachment,       XmATTACH_FORM,
589                 XmNtopOffset,           5,
590                 XmNcolumns,             40,
591                 NULL);
592         XtAddCallback(bl->username, XmNactivateCallback, blist_addname,
593                                 (XtPointer)c);
594         XtAddCallback(bl->username, XmNvalueChangedCallback, 
595                                 bl_pending_change, (XtPointer)c);
596
597         XtVaSetValues(bl->username_label,
598                 XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
599                 XmNbottomWidget,        bl->username,
600                 XmNbottomOffset,        5,
601                 XmNrightAttachment,     XmATTACH_WIDGET,
602                 XmNrightWidget,         bl->username,
603                 XmNrightOffset,         5,
604                 NULL);
605
606         label_str = XmStringCreateLocalized(
607                         catgets(c->DT_catd, 1, 688, "Browse Menu Items"));
608         bl->list_label = XtVaCreateWidget("list_label", 
609                 xmLabelWidgetClass, bl->form,
610                 XmNlabelString,         label_str,
611                 XmNtopAttachment,       XmATTACH_WIDGET,
612                 XmNtopWidget,           bl->username,
613                 XmNtopOffset,           10,
614                 XmNleftAttachment,      XmATTACH_FORM,
615                 XmNleftOffset,          5,
616                 NULL);
617         XmStringFree(label_str);
618
619         bl->message = XtVaCreateWidget("message_text",
620                 xmLabelGadgetClass, 
621                 bl->form,
622                 XmNalignment,           XmALIGNMENT_BEGINNING,
623                 XmNleftAttachment,      XmATTACH_FORM,
624                 XmNleftOffset,          5,
625                 XmNrightAttachment,     XmATTACH_FORM,
626                 XmNrightOffset,         5,
627                 XmNbottomAttachment,    XmATTACH_FORM,
628                 XmNbottomOffset,        5,
629                 NULL);
630
631         button_form = XtVaCreateWidget("menu_editor_button_form_mgr",
632                 xmFormWidgetClass,
633                 bl->form,
634                 XmNautoUnmanage,        False,
635                 XmNfractionBase,        5,
636                 XmNhorizontalSpacing,   5,
637                 XmNleftAttachment,      XmATTACH_FORM,
638                 XmNleftOffset,          5,
639                 XmNrightAttachment,     XmATTACH_FORM,
640                 XmNrightOffset,         5,
641                 XmNbottomAttachment,    XmATTACH_WIDGET,
642                 XmNbottomWidget,        bl->message,
643                 XmNbottomOffset,        5,
644                 NULL);
645         
646         label_str = XmStringCreateLocalized(catgets(c->DT_catd, 1, 655, "OK"));
647         bl->ok_button = XtVaCreateWidget("ok_button",
648                 xmPushButtonWidgetClass,
649                 button_form,
650                 XmNlabelString,         label_str,
651                 XmNleftAttachment,      XmATTACH_POSITION,
652                 XmNleftPosition,        0,
653                 XmNleftOffset,          5,
654                 XmNrightAttachment,     XmATTACH_POSITION,
655                 XmNrightPosition,       1,
656                 XmNrightOffset,         5,
657                 XmNbottomAttachment,    XmATTACH_FORM,
658                 NULL);
659         XmStringFree(label_str);
660         XtAddCallback(bl->ok_button, XmNactivateCallback, blist_ok,
661                                 (XtPointer)c);
662
663         label_str = XmStringCreateLocalized(
664                                 catgets(c->DT_catd, 1, 460, "Apply"));
665         bl->apply_button = XtVaCreateWidget("apply_button",
666                 xmPushButtonWidgetClass,
667                 button_form,
668                 XmNlabelString,         label_str,
669                 XmNleftAttachment,      XmATTACH_POSITION,
670                 XmNleftPosition,        1,
671                 XmNleftOffset,          5,
672                 XmNrightAttachment,     XmATTACH_POSITION,
673                 XmNrightPosition,       2,
674                 XmNrightOffset,         5,
675                 XmNbottomAttachment,    XmATTACH_FORM,
676                 NULL);
677         XmStringFree(label_str);
678         XtAddCallback(bl->apply_button, XmNactivateCallback, blist_apply,
679                                 (XtPointer)c);
680
681         label_str = XmStringCreateLocalized(
682                                 catgets(c->DT_catd, 1, 691, "Reset"));
683         bl->reset_button = XtVaCreateWidget("reset_button",
684                 xmPushButtonWidgetClass,
685                 button_form,
686                 XmNlabelString,         label_str,
687                 XmNleftAttachment,      XmATTACH_POSITION,
688                 XmNleftPosition,        2,
689                 XmNleftOffset,          5,
690                 XmNrightAttachment,     XmATTACH_POSITION,
691                 XmNrightPosition,       3,
692                 XmNrightOffset,         5,
693                 XmNbottomAttachment,    XmATTACH_FORM,
694                 NULL);
695         XmStringFree(label_str);
696         XtAddCallback(bl->reset_button, XmNactivateCallback,
697                         blist_reset_cb, (XtPointer)c);
698
699         label_str = XmStringCreateLocalized(
700                                 catgets(c->DT_catd, 1, 923, "Cancel"));
701         bl->cancel_button = XtVaCreateWidget("cancel_button",
702                 xmPushButtonWidgetClass,
703                 button_form,
704                 XmNlabelString,         label_str,
705                 XmNleftAttachment,      XmATTACH_POSITION,
706                 XmNleftPosition,        3,
707                 XmNleftOffset,          5,
708                 XmNrightAttachment,     XmATTACH_POSITION,
709                 XmNrightPosition,       4,
710                 XmNrightOffset,         5,
711                 XmNbottomAttachment,    XmATTACH_FORM,
712                 NULL);
713         XmStringFree(label_str);
714         XtAddCallback(bl->cancel_button, XmNactivateCallback, blist_cancel_cb,
715                                 (XtPointer)c);
716
717         label_str = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
718         bl->help_button = XtVaCreateWidget("help_button",
719                 xmPushButtonWidgetClass,
720                 button_form,
721                 XmNlabelString,         label_str,
722                 XmNleftAttachment,      XmATTACH_POSITION,
723                 XmNleftPosition,        4,
724                 XmNleftOffset,          5,
725                 XmNrightAttachment,     XmATTACH_POSITION,
726                 XmNrightPosition,       5,
727                 XmNrightOffset,         5,
728                 XmNbottomAttachment,    XmATTACH_FORM,
729                 NULL);
730         XmStringFree(label_str);
731         XtAddCallback(bl->help_button, XmNactivateCallback, 
732                 (XtCallbackProc)help_cb, MENU_EDITOR_HELP_BUTTON);
733         XtAddCallback(bl->form, XmNhelpCallback,
734                 (XtCallbackProc)help_cb, (XtPointer) MENU_EDITOR_HELP_BUTTON);
735
736         ManageChildren(button_form);
737
738         separator = XtVaCreateWidget("separator",
739                 xmSeparatorGadgetClass,
740                 bl->form,
741                 XmNleftAttachment,      XmATTACH_FORM,
742                 XmNrightAttachment,     XmATTACH_FORM,
743                 XmNbottomAttachment,    XmATTACH_WIDGET,
744                 XmNbottomWidget,        button_form,
745                 XmNbottomOffset,        5,
746                 NULL);
747         ac = 0;
748         XtSetArg(args[ac], XmNvisibleItemCount, 8); ++ac;
749         XtSetArg(args[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ++ac;
750         XtSetArg(args[ac], XmNdoubleClickInterval, 5); ++ac;
751         bl->browse_list = (Widget)XmCreateScrolledList(bl->form, "browse_list",
752                                                        args, ac);
753         bl->browse_list_sw = XtParent(bl->browse_list);
754
755         XtVaSetValues(bl->browse_list_sw,
756                 XmNvisualPolicy,        XmVARIABLE,
757                 XmNtopAttachment,       XmATTACH_WIDGET,
758                 XmNtopWidget,           bl->list_label,
759                 XmNtopOffset,           5,
760                 XmNleftAttachment,      XmATTACH_OPPOSITE_WIDGET,
761                 XmNleftWidget,          bl->list_label,
762                 XmNrightAttachment,     XmATTACH_OPPOSITE_WIDGET,
763                 XmNrightWidget,         bl->username,
764                 XmNrightOffset,         5,
765                 XmNbottomAttachment,    XmATTACH_WIDGET,
766                 XmNbottomWidget,        separator,
767                 XmNbottomOffset,        5,
768                 XmNwidth, 50,
769                 NULL);
770         XtManageChild(bl->browse_list);
771
772         XtAddCallback(bl->browse_list, XmNmultipleSelectionCallback, 
773                                 bl_list_selection_cb, (XtPointer)c);
774
775         ManageChildren(bl->form);
776         XtManageChild(bl->form);
777
778         /*
779          * Set default button
780          */
781         XtVaSetValues(bl->form, XmNcancelButton, bl->cancel_button, NULL);
782         XmProcessTraversal(bl->username, XmTRAVERSE_CURRENT);
783         XtVaSetValues(bl->form, XmNinitialFocus, bl->username, NULL);
784
785         /*
786          * For storing the list of names
787          */
788         if (!bl->blist_data)
789                 bl->blist_data = CmDataListCreate();
790 }
791
792 extern void
793 show_browselist(Calendar *c) {
794         Browselist      *bl;
795
796         if (c->browselist == NULL)
797                 c->browselist = (caddr_t)ckalloc(sizeof(Browselist));
798         bl = (Browselist *)c->browselist;
799
800         if (!bl->frame)
801                 make_browselist(c);
802         blist_reset(c);
803         XtVaSetValues(bl->frame, XmNmappedWhenManaged, True, NULL);
804         /*
805          * Set default button
806          */
807         XtVaSetValues(bl->form, XmNcancelButton, bl->cancel_button, NULL);
808         XmProcessTraversal(bl->username, XmTRAVERSE_CURRENT);
809         XtVaSetValues(bl->form, XmNinitialFocus, bl->username, NULL);
810
811         XtPopup(bl->frame, XtGrabNone);
812         set_message(bl->message, "\0");
813 }
814