1 /*******************************************************************************
5 ** $TOG: blist.c /main/5 1999/02/08 17:02:59 mgreess $
7 ** RESTRICTED CONFIDENTIAL INFORMATION:
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
17 ** Copyright 1993 Sun Microsystems, Inc. All rights reserved.
19 *******************************************************************************/
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. *
29 static char sccsid[] = "@(#)blist.c 1.66 95/03/28 Copyr 1994 Sun Microsystems, Inc.";
32 #include <EUSCompat.h>
35 #include <sys/param.h>
39 #include <Xm/LabelG.h>
41 #include <Xm/DialogS.h>
45 #include <Xm/RowColumn.h>
46 #include <Xm/SeparatoG.h>
58 bl_pending_change(Widget w, XtPointer data, XtPointer cbs) {
59 Calendar *c = (Calendar *) data;
60 Browselist *bl = (Browselist *)c->browselist;
62 if (bl->bl_pending_message_up == False) {
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.
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);
84 bl_clear_pending_change(Browselist *bl) {
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);
94 bl_list_is_changed(Browselist *bl) {
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);
106 bl_list_not_changed(Browselist *bl) {
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);
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;
121 XmListGetSelectedPos(bl->browse_list, &pos_list, &pos_cnt);
123 XtSetSensitive(bl->remove_button, False);
125 XtSetSensitive(bl->remove_button, True);
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
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;
141 set_message(bl->message, " ");
142 XmListGetSelectedPos(bl->browse_list, &pos_list, &pos_cnt);
144 set_message(bl->message, catgets(calendar->DT_catd, 1, 17,
145 "Select a name to remove"));
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"));
157 XmListDeletePos(bl->browse_list, pos_list[i] - i + rejected_name);
158 bd = (BlistData *)CmDataListGetData(bl->blist_data, pos_list[i]);
162 bd->tag = BLIST_DELETE;
165 blist_clean(bl, False);
166 bl_list_is_changed(bl);
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
175 blist_name_append(Calendar *c, char *name, BlistTag t) {
177 Boolean marked = False;
180 Browselist *bl = (Browselist *)c->browselist;
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
192 while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i)) &&
193 strcmp(bd->name, name) != 0)
195 if ((marked == False) && (strcoll(name, bd->name) < 0) &&
204 /* Since the user may have hit the reset button, any items
205 * that had been marked for deletion need to be made active.
207 if (bd->tag == BLIST_DELETE)
208 bd->tag = BLIST_ACTIVE;
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. */
218 defname = get_user_calendar();
219 if (strcmp(defname, name) == 0) {
221 } else if (marked == False) {
226 bd = (BlistData *)ckalloc(sizeof(BlistData));
227 bd->name = cm_strdup(name);
229 bd->cal_handle = NULL;
230 CmDataListAdd(bl->blist_data, (void *)bd, location);
237 * Callback for the add name button. This simply calls the blist_name_append
238 * function and adds the name to the UI.
241 blist_addname(Widget widget, XtPointer client_data, XtPointer cbs) {
242 char *new_name, *end_ptr, buf[MAXNAMELEN];
243 XEvent *e = ((XmAnyCallbackStruct *)cbs)->event;
245 Calendar *c = (Calendar *)client_data;
246 Browselist *bl = (Browselist *)c->browselist;
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);
256 /* crush out leading white space for the name
257 comparison/insert process */
259 while ((*new_name == ' ') || (*new_name == '\t'))
262 /* compress off trailing whitespace */
267 while ((end_ptr > new_name) &&
268 ((*(end_ptr - 1) == ' ') || (*(end_ptr - 1) == '\t')))
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"));
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"));
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);
291 cm_select_text(bl->username, e->xbutton.time);
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);
297 XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_ANY, NULL);
301 * This sends the new list of names to the properties database. Note it ignores
302 * items that have been tagged for deletion.
305 blist_write_list(Browselist *bl, Props *p) {
311 * First pass, count the number of bytes we're going to need
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 */
322 * We have names, so build the string, making sure to exclude items
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);
332 bd->tag = BLIST_ACTIVE;
335 set_char_prop(p, CP_DAYCALLIST, buf);
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.
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;
352 bl_clear_pending_change(bl);
353 bl_list_not_changed(bl);
354 set_message(bl->message, " ");
355 blist_write_list(bl, p);
357 XtVaSetValues(c->browse_button, XmNsubMenuId, NULL, NULL);
358 update_browse_menu_names(c);
359 XtVaSetValues(c->browse_button, XmNsubMenuId, c->browse_menu, NULL);
361 browser_reset_list(c);
363 XtPopdown(bl->frame);
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.
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;
378 bl_clear_pending_change(bl);
379 bl_list_not_changed(bl);
380 set_message(bl->message, " ");
381 blist_write_list(bl, p);
383 XtVaSetValues(c->browse_button, XmNsubMenuId, NULL, NULL);
384 update_browse_menu_names(c);
385 XtVaSetValues(c->browse_button, XmNsubMenuId, c->browse_menu, NULL);
387 browser_reset_list(c);
391 blist_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data) {
392 Calendar *c = (Calendar *)client_data;
393 Browselist *bl = (Browselist *)c->browselist;
397 XtPopdown(bl->frame);
401 blist_reset_cb(Widget widget, XtPointer client_data, XtPointer call_data) {
402 Calendar *c = (Calendar *)client_data;
403 Browselist *bl = (Browselist *)c->browselist;
409 blist_init_names(Calendar *c) {
410 char *name, *namelist;
411 Props *p = (Props*)c->properties;
412 Browselist *bl = (Browselist *)c->browselist;
415 bl->blist_data = CmDataListCreate();
418 * Make sure the default calendar is in list
420 name = get_user_calendar();
421 blist_name_append(c, name, BLIST_ACTIVE);
425 * Make sure user's calendar is in list
427 blist_name_append(c, c->calname, BLIST_ACTIVE);
429 /* make sure the intiial view name is in the list. */
431 blist_name_append(c, get_char_prop(p, CP_DEFAULTCAL), BLIST_ACTIVE);
433 namelist = cm_strdup(get_char_prop(p, CP_DAYCALLIST));
434 if (namelist == NULL || *namelist == NULL )
437 name = strtok(namelist, " ");
439 blist_name_append(c, name, BLIST_ACTIVE);
440 name = strtok(NULL, " ");
446 blist_init_ui(Calendar *c) {
450 Browselist *bl = (Browselist *)c->browselist;
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);
463 XmTextFieldSetString(bl->username, "");
464 XtVaSetValues(bl->form, XmNresizePolicy, XmRESIZE_ANY, NULL);
468 blist_clean(Browselist *bl, Boolean clean_all) {
469 int i, left_cnt = 1, cnt;
472 if (NULL == bl->blist_data) return;
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)) {
481 CmDataListDeletePos(bl->blist_data, left_cnt, True);
488 blist_reset(Calendar *c) {
489 Browselist *bl = (Browselist *)c->browselist;
491 blist_clean(bl, True);
494 bl_clear_pending_change(bl);
495 bl_list_not_changed(bl);
496 XtSetSensitive(bl->remove_button, False);
500 blist_quit_handler(Widget w, XtPointer cdata, XtPointer data) {
501 Browselist *bl = (Browselist *)cdata;
507 make_browselist(Calendar *c)
514 Browselist *bl = (Browselist *)c->browselist;
515 Dimension label_width;
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,
527 XmNallowShellResize, True,
528 XmNmappedWhenManaged, False,
530 setup_quit_handler(bl->frame, blist_quit_handler, (caddr_t)bl);
533 bl->form = XtVaCreateWidget("menu_editor_form",
534 xmFormWidgetClass, bl->frame,
535 XmNautoUnmanage, False,
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,
545 XmStringFree(label_str);
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);
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,
563 XmStringFree(label_str);
564 XtAddCallback(bl->add_button, XmNactivateCallback,
565 blist_addname, (XtPointer)c);
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,
574 XmStringFree(label_str);
575 XtAddCallback(bl->remove_button, XmNactivateCallback,
576 blist_removenames, (XtPointer)c);
577 ManageChildren(bl->edit_rc_mgr);
579 XtVaGetValues(bl->username_label, XmNwidth, &label_width, NULL);
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,
588 XmNtopAttachment, XmATTACH_FORM,
592 XtAddCallback(bl->username, XmNactivateCallback, blist_addname,
594 XtAddCallback(bl->username, XmNvalueChangedCallback,
595 bl_pending_change, (XtPointer)c);
597 XtVaSetValues(bl->username_label,
598 XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
599 XmNbottomWidget, bl->username,
601 XmNrightAttachment, XmATTACH_WIDGET,
602 XmNrightWidget, bl->username,
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,
614 XmNleftAttachment, XmATTACH_FORM,
617 XmStringFree(label_str);
619 bl->message = XtVaCreateWidget("message_text",
622 XmNalignment, XmALIGNMENT_BEGINNING,
623 XmNleftAttachment, XmATTACH_FORM,
625 XmNrightAttachment, XmATTACH_FORM,
627 XmNbottomAttachment, XmATTACH_FORM,
631 button_form = XtVaCreateWidget("menu_editor_button_form_mgr",
634 XmNautoUnmanage, False,
636 XmNhorizontalSpacing, 5,
637 XmNleftAttachment, XmATTACH_FORM,
639 XmNrightAttachment, XmATTACH_FORM,
641 XmNbottomAttachment, XmATTACH_WIDGET,
642 XmNbottomWidget, bl->message,
646 label_str = XmStringCreateLocalized(catgets(c->DT_catd, 1, 655, "OK"));
647 bl->ok_button = XtVaCreateWidget("ok_button",
648 xmPushButtonWidgetClass,
650 XmNlabelString, label_str,
651 XmNleftAttachment, XmATTACH_POSITION,
654 XmNrightAttachment, XmATTACH_POSITION,
657 XmNbottomAttachment, XmATTACH_FORM,
659 XmStringFree(label_str);
660 XtAddCallback(bl->ok_button, XmNactivateCallback, blist_ok,
663 label_str = XmStringCreateLocalized(
664 catgets(c->DT_catd, 1, 460, "Apply"));
665 bl->apply_button = XtVaCreateWidget("apply_button",
666 xmPushButtonWidgetClass,
668 XmNlabelString, label_str,
669 XmNleftAttachment, XmATTACH_POSITION,
672 XmNrightAttachment, XmATTACH_POSITION,
675 XmNbottomAttachment, XmATTACH_FORM,
677 XmStringFree(label_str);
678 XtAddCallback(bl->apply_button, XmNactivateCallback, blist_apply,
681 label_str = XmStringCreateLocalized(
682 catgets(c->DT_catd, 1, 691, "Reset"));
683 bl->reset_button = XtVaCreateWidget("reset_button",
684 xmPushButtonWidgetClass,
686 XmNlabelString, label_str,
687 XmNleftAttachment, XmATTACH_POSITION,
690 XmNrightAttachment, XmATTACH_POSITION,
693 XmNbottomAttachment, XmATTACH_FORM,
695 XmStringFree(label_str);
696 XtAddCallback(bl->reset_button, XmNactivateCallback,
697 blist_reset_cb, (XtPointer)c);
699 label_str = XmStringCreateLocalized(
700 catgets(c->DT_catd, 1, 923, "Cancel"));
701 bl->cancel_button = XtVaCreateWidget("cancel_button",
702 xmPushButtonWidgetClass,
704 XmNlabelString, label_str,
705 XmNleftAttachment, XmATTACH_POSITION,
708 XmNrightAttachment, XmATTACH_POSITION,
711 XmNbottomAttachment, XmATTACH_FORM,
713 XmStringFree(label_str);
714 XtAddCallback(bl->cancel_button, XmNactivateCallback, blist_cancel_cb,
717 label_str = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
718 bl->help_button = XtVaCreateWidget("help_button",
719 xmPushButtonWidgetClass,
721 XmNlabelString, label_str,
722 XmNleftAttachment, XmATTACH_POSITION,
725 XmNrightAttachment, XmATTACH_POSITION,
728 XmNbottomAttachment, XmATTACH_FORM,
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);
736 ManageChildren(button_form);
738 separator = XtVaCreateWidget("separator",
739 xmSeparatorGadgetClass,
741 XmNleftAttachment, XmATTACH_FORM,
742 XmNrightAttachment, XmATTACH_FORM,
743 XmNbottomAttachment, XmATTACH_WIDGET,
744 XmNbottomWidget, button_form,
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",
753 bl->browse_list_sw = XtParent(bl->browse_list);
755 XtVaSetValues(bl->browse_list_sw,
756 XmNvisualPolicy, XmVARIABLE,
757 XmNtopAttachment, XmATTACH_WIDGET,
758 XmNtopWidget, bl->list_label,
760 XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
761 XmNleftWidget, bl->list_label,
762 XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
763 XmNrightWidget, bl->username,
765 XmNbottomAttachment, XmATTACH_WIDGET,
766 XmNbottomWidget, separator,
770 XtManageChild(bl->browse_list);
772 XtAddCallback(bl->browse_list, XmNmultipleSelectionCallback,
773 bl_list_selection_cb, (XtPointer)c);
775 ManageChildren(bl->form);
776 XtManageChild(bl->form);
781 XtVaSetValues(bl->form, XmNcancelButton, bl->cancel_button, NULL);
782 XmProcessTraversal(bl->username, XmTRAVERSE_CURRENT);
783 XtVaSetValues(bl->form, XmNinitialFocus, bl->username, NULL);
786 * For storing the list of names
789 bl->blist_data = CmDataListCreate();
793 show_browselist(Calendar *c) {
796 if (c->browselist == NULL)
797 c->browselist = (caddr_t)ckalloc(sizeof(Browselist));
798 bl = (Browselist *)c->browselist;
803 XtVaSetValues(bl->frame, XmNmappedWhenManaged, True, NULL);
807 XtVaSetValues(bl->form, XmNcancelButton, bl->cancel_button, NULL);
808 XmProcessTraversal(bl->username, XmTRAVERSE_CURRENT);
809 XtVaSetValues(bl->form, XmNinitialFocus, bl->username, NULL);
811 XtPopup(bl->frame, XtGrabNone);
812 set_message(bl->message, "\0");