dtcm: Resolve CID 87562
[oweals/cde.git] / cde / programs / dtcm / dtcm / browser.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: browser.c /main/10 1999/02/23 09:42:01 mgreess $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <csa.h>
35 #include <X11/Xlib.h>
36 #include <Xm/Xm.h>
37 #include <Xm/DrawingA.h>
38 #include <Xm/Form.h>
39 #include <Xm/LabelG.h>
40 #include <Xm/List.h>
41 #include <Xm/DialogS.h>
42 #include <Xm/PanedW.h>
43 #include <Xm/Protocols.h>
44 #include <Xm/PushBG.h>
45 #include <Xm/RowColumn.h>
46 #include <Xm/Scale.h>
47 #include <Xm/SeparatoG.h>
48 #include <Xm/Text.h>
49 #include <Xm/ToggleBG.h>
50 #include <Xm/SashP.h>
51 #include <Dt/HourGlass.h>
52 #include <Tt/tttk.h>
53 #include "getdate.h"
54 #include "calendar.h"
55 #include "util.h"
56 #include "misc.h"
57 #include "timeops.h"
58 #include "browser.h"
59 #include "blist.h"
60 #include "format.h"
61 #include "datefield.h"
62 #include "props.h"
63 #include "props_pu.h"
64 #include "editor.h"
65 #include "group_editor.h"
66 #include "select.h"
67 #include "help.h"
68 #ifdef FNS
69 #include "cmfns.h"
70 #endif
71
72 #define DATESIZ 40
73
74 extern int debug;
75
76 static void mb_resize_proc(Widget, XtPointer, XtPointer);
77 static void cancel_cb(Widget, XtPointer, XtPointer);
78 static void popup_cb(Widget, XtPointer, XtPointer);
79 static void init_browser(Calendar *);
80 static void bcanvas_repaint(Widget, XtPointer, XtPointer);
81 static void bcanvas_event(Widget, XtPointer, XtPointer);
82 static void goto_date_cb(Widget, XtPointer, XtPointer);
83 static void browselist_from_browser(Widget, XtPointer, XtPointer);
84 static void gotomenu_cb(Widget, XtPointer, XtPointer);
85 static void schedule_cb(Widget, XtPointer, XtPointer);
86 static void mail_cb(Widget, XtPointer, XtPointer);
87 static void mb_box_notify(Widget, XtPointer, XtPointer);
88 static void mb_update_handler(CSA_session_handle, CSA_flags, CSA_buffer,
89                               CSA_buffer, CSA_extension *);
90
91 extern void scrub_attr_list(Dtcm_appointment *);
92
93 static void
94 mb_init_array(Browser *b, int begin, int end) {
95         b->segs_in_array = BOX_SEG * (end - begin) * 7;
96         b->multi_array = (char*)ckalloc(b->segs_in_array);
97 }
98
99 static void
100 reset_ticks(Calendar *c, Boolean use_sel_idx) {
101         int     beg, end;
102         Props   *p = (Props *)c->properties;
103         Browser *b = (Browser*)c->browser;
104
105         beg = get_int_prop(p, CP_DAYBEGIN);
106         end = get_int_prop(p, CP_DAYEND);
107
108         if (b->date <= get_bot()) {
109                 b->date = get_bot();
110                 if (b->col_sel > 0)
111                         b->col_sel = b->col_sel - 4;
112         }
113         if ((b->begin_week_tick = first_dow(b->date)) < get_bot())
114                 b->begin_week_tick = get_bot();
115         if (use_sel_idx) {
116                 b->begin_day_tick =
117                         next_ndays(b->begin_week_tick, b->col_sel);
118                 b->begin_hr_tick =
119                         next_nhours(b->begin_day_tick, beg + b->row_sel);
120         } else {
121                 b->begin_day_tick = lowerbound(b->date);
122                 b->begin_hr_tick = next_nhours(b->begin_day_tick, beg);
123         }
124         b->end_day_tick = upperbound(b->begin_day_tick);
125         b->end_hr_tick = next_nhours(b->begin_hr_tick, 1);
126 }
127
128 extern void
129 br_display(Calendar *c) {
130         int             i, *pos_list = NULL, pos_cnt;
131         Browser         *b = (Browser *)c->browser;
132         BlistData       *bd;
133         Browselist      *bl = (Browselist *)c->browselist;
134         void            mb_update_array();
135
136         if (!b)
137                 return;
138
139         for (i = 0; i < b->segs_in_array; i++)
140                 b->multi_array[i] = 0;
141         b->add_to_array = True;
142
143         XmListGetSelectedPos(b->browse_list, &pos_list, &pos_cnt);
144         for (i = 0; i < pos_cnt; i++) {
145                 bd = (BlistData *)CmDataListGetData(bl->blist_data,
146                                                     pos_list[i]);
147
148                 destroy_paint_cache(bd->cache, bd->cache_size);
149                 bd->cache = NULL;
150                 bd->cache_size = 0;
151
152                 if (bd)
153                         mb_update_array(bd->name, c);
154         }
155         if (pos_list)
156                 XtFree((XtPointer)pos_list);
157
158         mb_refresh_canvas(b, c);
159 }
160
161 static void
162 invalid_date_msg(Calendar *c, Widget widget)
163 {
164         Browser *b = (Browser*)c->browser;
165         char *title = XtNewString(catgets(c->DT_catd, 1, 1070, 
166                                   "Calendar : Error - Compare Calendars"));
167         char *text = XtNewString(catgets(c->DT_catd, 1, 20,
168                                          "Invalid Date In Go To Field."));
169         char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
170
171         dialog_popup(b->frame,
172                 DIALOG_TITLE, title,
173                 DIALOG_TEXT, text,
174                 BUTTON_IDENT, 1, ident,
175                 DIALOG_IMAGE, ((Props_pu *)c->properties_pu)->xm_error_pixmap,
176                 NULL);
177
178         XtFree(ident);
179         XtFree(text);
180         XtFree(title);
181 }
182
183 void 
184 set_entry_date(Calendar *c) {
185         char *date = NULL;
186         Browser *b;
187         Props *p;
188         OrderingType ot;
189         SeparatorType st;
190         Tick tick;
191
192         b = (Browser*)c->browser;
193         p = (Props*)c->properties;
194         ot = get_int_prop(p, CP_DATEORDERING);
195         st = get_int_prop(p, CP_DATESEPARATOR);
196
197         date = get_date_from_widget(c->view->date, b->datetext, ot, st);
198         if (date == NULL ) {
199                 invalid_date_msg(c, b->message_text);
200                 return;
201         }
202
203         tick = cm_getdate(date, NULL);
204         if (!timeok(tick)) {
205                 invalid_date_msg(c, b->message_text);
206                 return;
207         }
208
209         b->date = tick;
210         reset_ticks(c, False);
211         br_display(c);
212 }
213
214 /*
215  * A note about the browser:
216  * This custom dialog is built using two nested PanedWindowWidgets.
217  * The first child of the outer pane is itself paned (the other
218  * child is the dialog's action area).  The inner pane is movable
219  * to allow users to reproportion the calendar list versus the free
220  * time chart.  Most of the useful widget handles are stored in the
221  * Browser structure allocated and returned from here.
222  */
223 extern void
224 make_browser(Calendar *c)
225 {
226         Browser         *b;
227         Props           *p = (Props*) c->properties;
228         Widget          separator1;
229         Dimension       w, h, height;
230         XmString        xmstr;
231         XmString goto_label, prev_week, this_week, next_week, prev_month, next_month;
232         int             num_children;
233         Widget          *children;
234         OrderingType    ord_t = get_int_prop(p, CP_DATEORDERING);
235         SeparatorType   sep_t = get_int_prop(p, CP_DATESEPARATOR);
236         char            buf[BUFSIZ];
237         Widget          text_field_form;
238         int             outpane_width, outpane_height;
239         int             upform_min,item_count;
240         char            *title;
241
242         if (c->browser == NULL) {
243                 c->browser = (caddr_t)ckalloc(sizeof(Browser));
244                 b = (Browser*)c->browser;
245         }
246         else
247                 b = (Browser*)c->browser;
248
249         b->date = c->view->date;
250
251         mb_init_array(b, get_int_prop(p, CP_DAYBEGIN), get_int_prop(p, CP_DAYEND));
252         b->current_selection = (caddr_t) ckalloc(sizeof(Selection));
253
254         /* if the screen is small adjust the max size for width and height
255          * so the shell can be moved up and down using window facility
256          */
257         if ((WidthOfScreen(XtScreen(c->frame)) < 360) ||
258             (HeightOfScreen(XtScreen(c->frame)) < 600 ))
259         {
260                 outpane_width = 300;
261                 outpane_height = 430;
262                 item_count      = 3;
263                 upform_min      = 120;
264         }
265         else
266         {
267                 outpane_width = 360;
268                 outpane_height = 600;
269                 item_count      = 8;
270                 upform_min      = 200;
271         }
272
273         title = XtNewString(catgets(c->DT_catd, 1, 1010, 
274                                         "Calendar : Compare Calendars"));
275         b->frame = XtVaCreatePopupShell("frame",
276                 xmDialogShellWidgetClass, c->frame,
277                 XmNtitle, title,
278                 XmNallowShellResize, True,
279                 XmNmappedWhenManaged, False, 
280                 XmNdeleteResponse, XmDO_NOTHING,
281                 NULL);
282         XtFree(title);
283         XtAddCallback(b->frame, XmNpopupCallback, popup_cb, (XtPointer)c);
284
285
286         /*
287          * Create the outer pane, whose upper part will hold a
288          * nested pane, and whose lower part will hold the actions
289          * and message area
290          */
291         b->outer_pane = XtVaCreateManagedWidget("outerPane",
292                 xmPanedWindowWidgetClass, b->frame,
293                 XmNsashHeight, 1,
294                 XmNsashWidth, 1,
295                 XmNwidth, outpane_width,
296                 XmNheight, outpane_height,
297                 NULL);
298
299         b->inner_pane = XtVaCreateManagedWidget("innerPane",
300                 xmPanedWindowWidgetClass, b->outer_pane,
301                 XmNallowResize, True,
302                 NULL);
303
304         b->upper_form = XtVaCreateManagedWidget("upperForm",
305                 xmFormWidgetClass, b->inner_pane,
306                 XmNallowResize, True,
307                 XmNpaneMinimum, upform_min,
308                 NULL);
309
310         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 22, "Browse Menu Items"));
311         b->list_label = XtVaCreateWidget("browseMenuLabel", 
312                 xmLabelGadgetClass, b->upper_form,
313                 XmNlabelString, xmstr,
314                 XmNleftAttachment, XmATTACH_FORM,
315                 XmNtopAttachment, XmATTACH_FORM,
316                 XmNtopOffset, 10,
317                 NULL);
318         XmStringFree(xmstr);
319
320         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 21, "Edit List..."));
321         b->edit_list = XtVaCreateWidget("editList",
322                 xmPushButtonGadgetClass, b->upper_form,
323                 XmNlabelString, xmstr,
324                 XmNtopAttachment, XmATTACH_FORM,
325                 XmNrightAttachment, XmATTACH_FORM,
326                 XmNleftAttachment, XmATTACH_WIDGET,
327                 XmNleftWidget, b->list_label,
328                 XmNleftOffset, 80,
329                 NULL);
330         XmStringFree(xmstr);
331
332         XtAddCallback(b->edit_list, XmNactivateCallback,
333                 browselist_from_browser, (XtPointer)c);
334
335         b->browse_list = (Widget)XmCreateScrolledList(b->upper_form,
336                 "browseList", NULL, 0);
337         XtAddCallback(b->browse_list,
338                 XmNmultipleSelectionCallback, mb_box_notify, (XtPointer)c);
339         XtAddCallback(b->browse_list,
340                 XmNdefaultActionCallback, mb_box_notify, (XtPointer)c);
341         XtVaSetValues(b->browse_list,
342                 XmNselectionPolicy, XmMULTIPLE_SELECT,
343                 XmNvisibleItemCount, item_count,
344                 NULL);
345
346         b->browse_list_sw = XtParent(b->browse_list);
347         XtVaSetValues(b->browse_list_sw,
348                 XmNtopAttachment, XmATTACH_WIDGET,
349                 XmNtopWidget, b->edit_list,
350                 XmNleftAttachment, XmATTACH_FORM,
351                 XmNleftOffset, 20,
352                 XmNrightAttachment, XmATTACH_FORM,
353                 XmNrightOffset, 20,
354                 XmNbottomAttachment, XmATTACH_FORM,
355                 XmNvisualPolicy, XmVARIABLE,
356                 NULL);
357
358
359         /*
360          * Create the "go to" option menu for time navigation
361          */
362         prev_week =
363            XmStringCreateLocalized(catgets(c->DT_catd, 1, 23, "Prev Week"));
364         this_week =
365            XmStringCreateLocalized(catgets(c->DT_catd, 1, 24, "This Week"));
366         next_week =
367            XmStringCreateLocalized(catgets(c->DT_catd, 1, 25, "Next Week"));
368         prev_month =
369            XmStringCreateLocalized(catgets(c->DT_catd, 1, 26, "Prev Month"));
370         next_month =
371            XmStringCreateLocalized(catgets(c->DT_catd, 1, 27, "Next Month"));
372         goto_label =
373            XmStringCreateLocalized(catgets(c->DT_catd, 1, 28, "Go To:"));
374
375         /*
376          * remember - this returns a RowColumn widget!
377          */
378         b->gotomenu = XmVaCreateSimpleOptionMenu(b->upper_form,
379                 "goToOptionMenu", goto_label, 0, 0, gotomenu_cb,
380                 XmVaPUSHBUTTON, prev_week, NULL, NULL, NULL,
381                 XmVaPUSHBUTTON, this_week, NULL, NULL, NULL,
382                 XmVaPUSHBUTTON, next_week, NULL, NULL, NULL,
383                 XmVaPUSHBUTTON, prev_month, NULL, NULL, NULL,
384                 XmVaPUSHBUTTON, next_month, NULL, NULL, NULL,
385                 XmNbottomAttachment, XmATTACH_FORM,
386                 XmNbottomOffset, 5,
387                 XmNleftAttachment, XmATTACH_FORM,
388                 XmNleftOffset, 20,
389                 XmNuserData, c,
390                 XmNnavigationType, XmTAB_GROUP,
391                 NULL);
392         XmStringFree(prev_week);
393         XmStringFree(this_week);
394         XmStringFree(next_week);
395         XmStringFree(prev_month);
396         XmStringFree(next_month);
397         XmStringFree(goto_label);
398
399         text_field_form = XtVaCreateManagedWidget("text_field_form",
400                 xmFormWidgetClass, b->upper_form,
401                 XmNbottomAttachment, XmATTACH_FORM,
402                 XmNbottomOffset, 5,
403                 XmNleftAttachment, XmATTACH_WIDGET,
404                 XmNleftWidget, b->gotomenu,
405                 NULL);
406
407         b->datetext = XtVaCreateWidget("dateText",
408                 xmTextWidgetClass, text_field_form,
409                 NULL);
410         XtAddCallback(b->datetext, XmNactivateCallback, goto_date_cb, 
411                                                                 (XtPointer)c);
412
413         /*
414          * We can now calc the proper offset for the bottom of scrolled
415          * list - allow for a small margin above and below the text field.
416          */
417         XtVaGetValues(b->datetext, XmNheight, &height, NULL);
418         XtVaSetValues(b->browse_list_sw, XmNbottomOffset, (height + 10), NULL);
419
420         b->lower_form = XtVaCreateManagedWidget("lowerForm",
421                 xmFormWidgetClass, b->inner_pane,
422                 XmNallowResize, True,
423                 XmNpaneMinimum, 200,
424                 XmNtraversalOn, False,
425                 NULL);
426
427         /*
428          * create drawing area for chart
429          */
430         b->canvas = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass,
431                 b->lower_form,
432                 XmNtopAttachment, XmATTACH_FORM,
433                 XmNleftAttachment, XmATTACH_FORM,
434                 XmNrightAttachment, XmATTACH_FORM,
435                 XmNbottomAttachment, XmATTACH_FORM,
436                 XmNtraversalOn, False,
437                 NULL);
438         b->xcontext = gr_create_xcontext(c, b->canvas, gr_color,
439                 c->xcontext->app);
440
441         XtVaSetValues(b->canvas, XmNheight, 300, NULL);
442
443         XtAddCallback(b->canvas, XmNresizeCallback, mb_resize_proc, (XtPointer)c);
444         XtAddCallback(b->canvas, XmNinputCallback, bcanvas_event, (XtPointer)c);
445         XtAddCallback(b->canvas, XmNexposeCallback, bcanvas_repaint, (XtPointer)c);
446
447         /*
448          * Create action area of the dialog
449          */
450         b->action = XtVaCreateWidget("action",
451                 xmFormWidgetClass, b->outer_pane,
452                 NULL);
453
454         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 29, "Schedule..."));
455         b->schedule = XtVaCreateWidget("schedule",
456                 xmPushButtonGadgetClass, b->action,
457                 XmNlabelString, xmstr,
458                 XmNtopAttachment, XmATTACH_FORM,
459                 XmNleftAttachment, XmATTACH_FORM,
460                 NULL);
461         XmStringFree(xmstr);
462         XtAddCallback(b->schedule, XmNactivateCallback, schedule_cb, (XtPointer)c);
463
464         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 30, "Mail..."));
465         b->mail = XtVaCreateWidget("mail",
466                 xmPushButtonGadgetClass, b->action,
467                 XmNlabelString, xmstr,
468                 XmNleftAttachment, XmATTACH_WIDGET,
469                 XmNleftWidget, b->schedule,
470                 XmNtopAttachment, XmATTACH_FORM,
471                 NULL);
472         XmStringFree(xmstr);
473         XtAddCallback(b->mail, XmNactivateCallback, mail_cb, (XtPointer)c);
474
475         XtSetSensitive(b->mail, c->tt_procid == NULL ? False : True);
476
477         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 923, "Cancel"));
478         b->cancel = XtVaCreateWidget("cancel",
479                 xmPushButtonGadgetClass, b->action,
480                 XmNlabelString, xmstr,
481                 XmNleftAttachment, XmATTACH_WIDGET,
482                 XmNleftWidget, b->mail,
483                 XmNtopAttachment, XmATTACH_FORM,
484                 NULL);
485         XmStringFree(xmstr);
486         XtAddCallback(b->cancel, XmNactivateCallback, cancel_cb, (XtPointer)c);
487
488         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
489         b->helpbutton = XtVaCreateWidget("help",
490                 xmPushButtonGadgetClass, b->action,
491                 XmNlabelString, xmstr,
492                 XmNleftAttachment, XmATTACH_WIDGET,
493                 XmNleftWidget, b->cancel,
494                 XmNtopAttachment, XmATTACH_FORM,
495                 NULL);
496         XmStringFree(xmstr);
497         XtAddCallback(b->helpbutton, XmNactivateCallback,
498                 (XtCallbackProc)help_cb, COMPARE_CALS_HELP_BUTTON);
499         XtAddCallback(b->action, XmNhelpCallback,
500                 (XtCallbackProc)help_cb, (XtPointer) COMPARE_CALS_HELP_BUTTON);
501
502         b->message_text = XtVaCreateWidget("message",
503                 xmLabelGadgetClass, b->action,
504                 XmNtopAttachment, XmATTACH_WIDGET,
505                 XmNtopWidget, b->schedule,
506                 XmNleftAttachment, XmATTACH_FORM,
507                 XmNrightAttachment, XmATTACH_FORM,
508                 XmNbottomAttachment, XmATTACH_FORM,
509                 XmNalignment, XmALIGNMENT_BEGINNING,
510                 NULL);
511
512         /*
513          * Fix the size of action area
514          */
515         XtVaGetValues(b->schedule, XmNheight, &height, NULL);
516         XtVaSetValues(b->action,
517                 XmNpaneMaximum, (2*height),
518                 XmNpaneMinimum, (2*height),
519                 NULL);
520
521
522         XtVaGetValues(b->outer_pane,
523                 XmNchildren, &children,
524                 XmNnumChildren, &num_children,
525                 NULL);
526
527         while (num_children-- > 0) {
528                 if (XmIsSash(children[num_children])) {
529                                 XtVaSetValues(children[num_children], XmNtraversalOn, False, NULL);
530                 }
531         }
532
533         XtManageChild(b->edit_list);
534         XtManageChild(b->list_label);
535         XtManageChild(b->browse_list);
536         XtManageChild(b->gotomenu);
537         XtManageChild(b->datetext);
538         XtManageChild(b->schedule);
539         XtManageChild(b->mail);
540         XtManageChild(b->cancel);
541         XtManageChild(b->helpbutton);
542         XtManageChild(b->message_text);
543         XtManageChild(b->action);
544
545         gr_init(b->xcontext, b->canvas);
546
547         format_tick(b->date, ord_t, sep_t, buf);
548         XmTextSetString(b->datetext, buf);
549
550         set_entry_date(c);
551
552         /*
553          * set default button for dialog
554          */
555         XtVaSetValues(b->action, XmNdefaultButton, b->schedule, NULL);
556         XtVaSetValues(b->upper_form, XmNdefaultButton, b->schedule, NULL);
557
558         /* We don't want a ``return'' in the text field to trigger the
559          * default action so we create a form around the text field and
560          * designate the text-field as the default button.
561          */
562         XtVaSetValues(text_field_form, XmNdefaultButton, b->datetext, NULL);
563
564         XtVaSetValues(b->action, XmNcancelButton, b->cancel, NULL);
565         XtVaSetValues(b->upper_form, XmNcancelButton, b->cancel, NULL);
566         XmProcessTraversal(b->schedule, XmTRAVERSE_CURRENT);
567         XtVaSetValues(b->action, XmNinitialFocus, b->schedule, NULL);
568
569         XtVaSetValues(b->frame, XmNmappedWhenManaged, True, NULL);
570         XtRealizeWidget(b->frame);
571         /*
572          * Enforce a "reasonable" size.
573          * too narrow and the buttons are erased
574          * too short and the chart will look smashed
575         XtVaSetValues(b->frame,
576                 XmNminWidth, 300,
577                 XmNminHeight, 600,
578                 NULL);
579          */
580
581         /*
582         * Add a WM protocol callback to handle the
583         * case where the window manager closes the dialog.
584         * Pass the calendar ptr through client data to allow
585         * the callback to get at the shell and destroy it.
586         */
587         setup_quit_handler(b->frame, cancel_cb, (XtPointer)c);
588
589         init_browser(c);
590 }
591
592 static void 
593 browselist_from_browser(Widget w, XtPointer client_data, XtPointer call_data)
594 {
595         Calendar *c = (Calendar *)client_data;
596         Browselist      *bl;
597
598         bl = (Browselist *)c->browselist;
599
600         show_browselist(c);
601 }
602
603 static void
604 goto_date_cb(Widget w, XtPointer client_data, XtPointer call_data) 
605 {
606         Calendar *c = (Calendar *)client_data;
607         Browser *b;
608
609         set_entry_date(c);
610 }
611
612 static void
613 goto_unit(Calendar *c, int item_no)
614 {
615         char buf[DATESIZ];
616         Browser *b;
617         Props *p;
618         OrderingType    ord_t;
619         SeparatorType   sep_t;
620
621         b = (Browser*)c->browser;
622         p = (Props*)c->properties;
623
624         switch (item_no + 1) {
625         case MB_PREVWEEK:
626                 b->date = last_ndays(b->date, 7);
627                 break;
628         case MB_THISWEEK:
629                 b->date = now();
630                 break;
631         case MB_NEXTWEEK:
632                 b->date = next_ndays(b->date, 7);
633                 break;
634         case MB_NEXTMONTH:
635                 b->date = next_ndays(b->date, 28);
636                 break;
637         case MB_PREVMONTH:
638                 b->date = last_ndays(b->date, 28);
639                 break;
640         default:
641                 b->date = now();
642                 break;
643         }
644
645         reset_ticks(c, False);
646
647         ord_t = get_int_prop(p, CP_DATEORDERING);
648         sep_t = get_int_prop(p, CP_DATESEPARATOR);
649
650         format_tick(b->date, ord_t, sep_t, buf);
651         XmTextSetString(b->datetext, buf);
652         br_display(c);
653 }
654
655 static void
656 bcanvas_repaint(Widget w, XtPointer client_data, XtPointer call_data)
657 {
658         Calendar *c = (Calendar *)client_data;
659         Browser *b;
660         XRectangle clip;
661         XEvent ev;
662         new_XContext    *xc;
663         XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)call_data;
664
665         /* repair in full on final exposure (crude optimization scheme) */
666         if (cbs->event->xexpose.count != 0)
667            return;
668
669         b = (Browser *)c->browser;
670         if ((xc = b->xcontext)==NULL)
671                 return;
672
673         clip.x = 0;
674         clip.y = 0;
675         XtVaGetValues(w, XmNwidth, &clip.width, XmNy, &clip.height, NULL);
676
677         gr_set_clip_rectangles(xc, 0, 0, &clip, 1, Unsorted);
678
679         gr_clear_area(b->xcontext, 0, 0, b->canvas_w, b->canvas_h);
680         gr_clear_clip_rectangles(xc);
681         mb_refresh_canvas(b, c);
682  
683         XSync(XtDisplay(b->canvas), 0);
684 }
685
686 static void
687 mb_display_footermess(Browser *b, Calendar *c)
688 {
689         int num_cals;
690         char buf[BUFSIZ];
691
692         XtVaGetValues(b->browse_list, XmNselectedItemCount, &num_cals, NULL);
693         if (num_cals == 1)
694                 sprintf(buf, "%d %s", num_cals,
695                         catgets(c->DT_catd, 1, 31, "Calendar Displayed"));
696         else
697                 sprintf(buf,  "%d %s", num_cals,
698                         catgets(c->DT_catd, 1, 32, "Calendars Displayed"));
699         set_message(b->message_text, buf);
700 }
701
702 static void
703 browser_to_gaccess_list(Calendar *c) {
704         int             i, pos_cnt, *pos_list = NULL;
705         GEditor         *ge = (GEditor *)c->geditor;
706         Browser         *b = (Browser *)c->browser;
707         BlistData       *bd;
708         Browselist      *bl = (Browselist *)c->browselist;
709
710         /*
711          *  Add selected items to list box in group appt editor
712          */
713         XmListGetSelectedPos(b->browse_list, &pos_list, &pos_cnt);
714         for (i = 0; i < pos_cnt; i++) {
715                 if (bd = (BlistData *)CmDataListGetData(bl->blist_data,
716                                                         pos_list[i]))
717                         add_to_gaccess_list(bd->name, bd->cal_handle,
718                                 bd->user_access, bd->version, ge, True);
719         }
720         add_all_gappt(ge);
721         if (pos_cnt > 0)
722                 XtFree((XtPointer)pos_list);
723 }
724
725 void mb_update_busystatus(Browser *b, Calendar *c)
726 {
727         int                     i, j, r_cnt;
728         CSA_uint32              num_entries;
729         char                    buf[BUFSIZ + 5];
730         Boolean                 match = False;
731         XmString                xmstr;
732         Browselist              *bl = (Browselist *)c->browselist;
733         time_t                  start, stop;
734         CSA_entry_handle        *entries = NULL;
735         BlistData               *bd;
736         CSA_return_code         stat;
737         CSA_enum                *ops;
738         CSA_attribute           *range_attrs;
739         Tick                    start_tick, end_tick;
740
741         j = 1;
742         while (bd = (BlistData *)CmDataListGetData(bl->blist_data, j)) {
743                 if (!XmListPosSelected(b->browse_list, j++))
744                         continue;
745
746                 sprintf(buf, "  %s", bd->name);
747                 start = b->begin_day_tick;
748                 stop = b->end_hr_tick;
749
750                 if (bd->cache == NULL) {
751                         setup_range(&range_attrs, &ops, &r_cnt, start, stop, 
752                                         CSA_TYPE_EVENT, 0, B_FALSE, bd->version);
753                         stat = csa_list_entries(bd->cal_handle, r_cnt, range_attrs, ops, &num_entries, &entries, NULL);
754                                 free_range(&range_attrs, &ops, r_cnt);
755                         backend_err_msg(b->frame, bd->name, stat,
756                                         ((Props_pu *)c->properties_pu)->xm_error_pixmap);
757                         if (stat != CSA_SUCCESS) {
758                                 csa_free(entries);
759                                 return;
760                         }
761
762                         allocate_paint_cache(entries, num_entries, &bd->cache);
763                         bd->cache_size = num_entries;
764                         csa_free(entries);
765                 }
766
767                 for (i = 0; i < bd->cache_size; i++) {
768
769                         start_tick = bd->cache[i].start_time;
770                         end_tick = bd->cache[i].end_time;
771                         if ((start_tick+1 <= b->end_hr_tick) && 
772                             (end_tick-1 
773                                 >= b->begin_hr_tick)) {
774                                 buf[0] = '*';
775                                 break;
776                         }
777
778                 } /* end for */
779
780                 xmstr = XmStringCreateLocalized(buf);
781                 XmListDeletePos(b->browse_list, j-1);
782                 XmListAddItem(b->browse_list, xmstr, j-1);
783                 XmListSelectPos(b->browse_list, j-1, False);
784                 XmStringFree(xmstr);
785         } /* end while */
786 }
787
788 static void
789 bcanvas_event(Widget w, XtPointer client_data, XtPointer call_data)
790 {
791         Calendar *c = (Calendar *)client_data;
792         Browser *b;
793         XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*) call_data;
794         XEvent  *event = cbs->event;
795         Tick start;
796         static XEvent lastevent;
797         int x, y, boxw, boxh;
798         pr_pos xy;
799
800         if ((event->type == ButtonRelease) || (event == NULL))
801                 return;
802
803         b = (Browser*)c->browser;
804
805         x       = event->xbutton.x;
806         y       = event->xbutton.y;
807
808         switch(event->type) {
809         case ButtonPress:
810                 if (x > b->chart_x && y > b->chart_y &&
811                         x < (b->chart_x + b->chart_width)
812                         && y < (b->chart_y + b->chart_height))
813                 {
814                         browser_deselect(c, b);
815                         b->col_sel = (x - b->chart_x) / b->boxw;
816                         b->row_sel = (y - b->chart_y) / b->boxh;
817                         xy.x = b->col_sel;
818                         xy.y = b->row_sel;
819
820                         /*
821                          *  Don't bring up multi-browser for an invalid date
822                          */
823                         if ((last_ndays(b->date, 2) <= get_bot()) &&
824                             (b->col_sel < 3))
825                                 return;
826                         else if ((next_ndays(b->date, 1) > get_eot()) &&
827                                  (b->col_sel > 3))
828                                 return;
829  
830                         reset_ticks(c, True);
831                         browser_select(c, b, &xy);
832                         if (ds_is_double_click(&lastevent, event)) {
833                                 _DtTurnOnHourGlass(b->frame);
834                                 show_geditor(c, b->begin_hr_tick,
835                                              b->end_hr_tick);
836                                 browser_to_gaccess_list(c);
837                                 _DtTurnOffHourGlass(b->frame);
838                         }
839                         /* add busyicon */
840                         mb_update_busystatus(b, c);
841                 }
842                 c->general->last_canvas_touched = browser;
843         };
844         lastevent = *event;
845 }
846
847 static void
848 schedule_cb(Widget w, XtPointer client_data, XtPointer call_data)
849 {
850         Calendar *c = (Calendar *)client_data;
851         Browser *b;
852         Props *p;
853         OrderingType    ord_t;
854         SeparatorType   sep_t;
855         XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct*) call_data;
856
857         b = (Browser *)c->browser;
858         p = (Props *)c->properties;
859         _DtTurnOnHourGlass(b->frame);
860         ord_t = get_int_prop(p, CP_DATEORDERING);
861         sep_t = get_int_prop(p, CP_DATESEPARATOR);
862         show_geditor(c, b->begin_hr_tick, b->end_hr_tick);
863         browser_to_gaccess_list(c);
864         _DtTurnOffHourGlass(b->frame);
865 }
866
867
868 static char *
869 get_mail_address_list(Calendar *c) {
870         int             i, *pos_list = NULL, pos_cnt;
871         Browser         *b = (Browser *)c->browser;
872         BlistData       *bd;
873         Browselist      *bl = (Browselist *)c->browselist;
874         int             address_len;
875         char            *address;
876
877
878         XmListGetSelectedPos(b->browse_list, &pos_list, &pos_cnt);
879         for (i = 0, address_len = 0; i < pos_cnt; i++) {
880                 bd = (BlistData *)CmDataListGetData(bl->blist_data,
881                                                     pos_list[i]);
882                 if (bd)
883                         address_len += strlen(bd->name) + 1;
884         }
885
886         address = calloc(address_len+1, 1);
887         address[0] = '\0';
888
889         for (i = 0; i < pos_cnt; i++) {
890                 bd = (BlistData *)CmDataListGetData(bl->blist_data,
891                                                     pos_list[i]);
892                 if (bd) {
893                         strcat(address, bd->name);
894                         strcat(address, " ");
895                 }
896         }
897         if (pos_list)
898                 XtFree((XtPointer)pos_list);
899
900         return(address);
901 }
902
903 static Tt_message
904 reply_cb(Tt_message m, void *c_data, Tttk_op op, unsigned char *contents, int len, char *file)
905 {
906         char *client_procID = tt_message_handler(m);
907         if ( debug && (client_procID != NULL) ) {
908                 fprintf(stderr, "DEBUG: reply_cb():client_procID = %s\n", client_procID);
909                 fprintf(stderr, "DEBUG: reply_cb():message_op = %s\n", tt_message_op(m));
910         }
911         return(m);
912 }
913
914 static void
915 mail_cb(Widget w, XtPointer client_data, XtPointer call_data)
916 {
917         Calendar        *c = (Calendar *)client_data;
918         Props           *p = (Props *) c->properties;
919         Browser         *b = (Browser *)c->browser;
920         Tt_message      msg;
921         Tt_status       status;
922         char            *appointment_buf;
923         Dtcm_appointment        *appt;
924         char            *address = get_mail_address_list(c);
925         char            *address_list[1];
926         char            *mime_buf;
927  
928         /* Send ToolTalk message to bring up compose GUI with buffer as attachme
929 nt */
930
931         appt = allocate_appt_struct(appt_write, DATAVER_ARCHIVE, NULL);
932         load_appt_defaults(appt, p);
933
934         appt->time->value->item.date_time_value = malloc(BUFSIZ);
935         _csa_tick_to_iso8601(b->begin_hr_tick, appt->time->value->item.date_time_value);
936         appt->end_time->value->item.date_time_value = malloc(BUFSIZ);
937         _csa_tick_to_iso8601(b->end_hr_tick, appt->end_time->value->item.date_time_value);
938
939         /* set up the start time from the dialog */
940
941         scrub_attr_list(appt);
942  
943         appointment_buf = parse_attrs_to_string(appt, p, attrs_to_string(appt->attrs, appt->count));
944
945         free_appt_struct(&appt);
946
947         address_list[0] = appointment_buf;
948  
949         mime_buf = create_rfc_message(address, "message", address_list, 1);
950
951         msg = ttmedia_load(0, (Ttmedia_load_msg_cb)reply_cb, NULL, TTME_MAIL_EDIT, "RFC_822_MESSAGE", (unsigned char *)mime_buf, strlen(mime_buf), NULL, "dtcm_appointment_attachment", 0);
952  
953         status = tt_ptr_error(msg);
954         if (tt_is_err(status))
955         {
956             fprintf(stderr, "dtcm: ttmedia_load: %s\n",
957                     tt_status_message(status));
958         }
959         else
960         {
961             status = tt_message_send(msg);
962             if (tt_is_err(status))
963                 fprintf(stderr, "dtcm: tt_message_send: %s\n",
964                         tt_status_message(status));
965         }
966
967         free(appointment_buf);
968         free(mime_buf);
969         free(address);
970 }
971
972 static void
973 gotomenu_cb(Widget w, XtPointer data, XtPointer cbs) 
974 {
975         int     item_no = (int) (intptr_t) data;
976         /* should really be getting this from the widget */
977         Calendar *c = calendar;
978
979         goto_unit(c, item_no);
980 }
981
982 extern void
983 mb_update_segs(Browser *b, Tick tick, Tick dur, int *start_index, int *end_index)
984 {
985         int     num_segs, i, start, start_hour, duration, nday;
986         Props *p;
987  
988         p = (Props*)calendar->properties;
989  
990         start_hour = hour(tick);
991         
992         if (start_hour >= get_int_prop(p, CP_DAYEND)) {
993                 *start_index = -1;
994                 *end_index = -1;
995                 return;
996         }
997  
998         if (start_hour < get_int_prop(p, CP_DAYBEGIN)) {
999                 start = 0;
1000                 duration = dur - ((double)(get_int_prop(p, CP_DAYBEGIN) -
1001                  ((double)start_hour + (double)minute(tick)/(double)60))
1002                         * (double)hrsec);
1003         } else{
1004                 start = ((double)(start_hour - get_int_prop(p, CP_DAYBEGIN)) *
1005                         (double)60 + (double)minute(tick));
1006                 duration = dur;
1007         }
1008  
1009         if (duration <= 0) {
1010                 *start_index = -1;
1011                 *end_index = -1;
1012                 return;
1013         }
1014         nday = (nday=dow(tick))==0? 6: nday-1;
1015         num_segs = (double)start / (double)MINS_IN_SEG;
1016         *start_index = (double)start / (double)MINS_IN_SEG + (nday * (b->segs_in_array/7));
1017         if (start - (num_segs * MINS_IN_SEG) > 7)
1018                 (*start_index)++;
1019         num_segs = ((double)duration / (double)60 / (double)MINS_IN_SEG);
1020         *end_index = num_segs + *start_index;
1021         if (((double)duration/(double)60-MINS_IN_SEG*num_segs) > 7)
1022                 (*end_index)++;
1023  
1024         if (*end_index > (i = ((nday + 1) * (b->segs_in_array / 7))) )
1025                 *end_index = i;
1026  
1027         for (i = *start_index; i < *end_index; i++)
1028                 if (b->add_to_array)
1029                         b->multi_array[i]++;
1030                 else if (b->multi_array[i] > 0)
1031                         b->multi_array[i]--;
1032 }
1033
1034 void
1035 mb_update_array(char *entry_text, Calendar *c)
1036 {
1037         int                     start_ind, end_ind, i, r_cnt;
1038         time_t                  start, stop;
1039         Browser                 *b = (Browser *)c->browser;
1040         CSA_entry_handle        *entries = NULL;
1041         BlistData               *bd;
1042         CSA_return_code         stat;
1043         Browselist              *bl = (Browselist *)c->browselist;
1044         CSA_enum                *ops;
1045         CSA_attribute           *range_attrs;
1046         CSA_uint32      num_entries;
1047         Tick                    start_tick, end_tick;
1048
1049         /*
1050          *  Search for the entry text in our list of calendar handles
1051          */
1052         i = 1;
1053         while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i++))
1054                && strcmp(bd->name, entry_text) != 0);
1055         if (!bd)
1056                 return;
1057
1058         start = b->begin_week_tick;
1059         stop = next_ndays(b->begin_week_tick, 7) - 1;
1060
1061         if (bd->cache == NULL) {
1062                 setup_range(&range_attrs, &ops, &r_cnt, start, 
1063                         stop, CSA_TYPE_EVENT,
1064                         0, B_FALSE, bd->version);
1065                 stat = csa_list_entries(bd->cal_handle, r_cnt, range_attrs, 
1066                                         ops, &num_entries, &entries, NULL);
1067                 free_range(&range_attrs, &ops, r_cnt);
1068                 backend_err_msg(b->frame, bd->name, stat,
1069                                 ((Props_pu *)c->properties_pu)->xm_error_pixmap);
1070                 if (stat != CSA_SUCCESS)
1071                         return;
1072
1073                 allocate_paint_cache(entries, num_entries, &bd->cache);
1074                 bd->cache_size = num_entries;
1075                 csa_free(entries);
1076
1077         }
1078
1079         for (i = 0; i < bd->cache_size; i++) {
1080
1081                 start_tick = bd->cache[i].start_time;
1082                 end_tick = bd->cache[i].end_time;
1083
1084                 mb_update_segs(b, start_tick,
1085                                end_tick - start_tick, &start_ind,
1086                                &end_ind);
1087         }
1088 }
1089
1090 static Boolean
1091 register_names(char *name, Calendar *c)
1092 {
1093         int             i;
1094         char            *user, *location;
1095         Props_pu        *p = (Props_pu *)c->properties_pu;
1096         Browser         *b = (Browser*)c->browser;
1097         BlistData       *bd = NULL;
1098         Browselist      *bl = (Browselist *)c->browselist;
1099         CSA_return_code stat;
1100         CSA_session_handle      cal = NULL;
1101         unsigned int            user_access;
1102         CSA_calendar_user       csa_user;
1103         CSA_flags               flags = NULL;
1104         CSA_extension           cb_ext;
1105         CSA_extension           logon_ext;
1106         char                    buf[BUFSIZ];
1107
1108         if (blank_buf(name))
1109                 return False;
1110
1111         i = 1;
1112         while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i++))
1113                && strcmp(bd->name, name) != 0);
1114         if (!bd) {
1115                 char *title = XtNewString(catgets(c->DT_catd, 1, 1070,
1116                                 "Calendar : Error - Compare Calendars"));
1117                 char *text = XtNewString(catgets(c->DT_catd, 1, 607,
1118                                 "Internal error registering calendar name."));
1119                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1120                 dialog_popup(b->frame,
1121                         DIALOG_TITLE, title,
1122                         DIALOG_TEXT, text,
1123                         BUTTON_IDENT, 1, ident,
1124                         DIALOG_IMAGE, p->xm_error_pixmap,
1125                         NULL);
1126                 XtFree(ident);
1127                 XtFree(text);
1128                 XtFree(title);
1129                 return False;
1130         }
1131         if (bd->cal_handle)
1132                 return True;
1133
1134         if (strcmp(c->calname, name) == 0) {
1135                 cal = c->my_cal_handle;
1136                 user_access = c->my_access;
1137         } else if (strcmp(c->view->current_calendar, name) == 0) {
1138                 cal = c->cal_handle;
1139                 user_access = c->user_access;
1140         } else {
1141                 user = cm_target2name(name);
1142                 location = cm_target2location(name);
1143                 csa_user.user_name = name;
1144                 csa_user.user_type = 0;
1145                 csa_user.calendar_user_extensions = NULL;
1146                 csa_user.calendar_address = name;
1147                 logon_ext.item_code = CSA_X_DT_GET_USER_ACCESS_EXT;
1148                 logon_ext.item_data = 0;
1149                 logon_ext.item_reference = NULL;
1150                 logon_ext.extension_flags = CSA_EXT_LAST_ELEMENT;
1151                 stat = csa_logon(NULL, &csa_user, NULL, NULL, NULL, &cal,
1152                         &logon_ext);
1153                 free(user);
1154                 free(location);
1155  
1156                 if (stat != CSA_SUCCESS) {
1157                         backend_err_msg(b->frame, name, stat,
1158                                ((Props_pu *)c->properties_pu)->xm_error_pixmap);
1159                         return False;
1160                 } else
1161                         user_access = logon_ext.item_data;
1162
1163         }
1164
1165         /* register for activity notification */
1166         flags = CSA_CB_ENTRY_ADDED | CSA_CB_ENTRY_UPDATED |
1167                 CSA_CB_ENTRY_DELETED;
1168         cb_ext.item_code = CSA_X_XT_APP_CONTEXT_EXT;
1169         cb_ext.item_data = (CSA_uint32)c->xcontext->app;
1170         cb_ext.extension_flags = CSA_EXT_LAST_ELEMENT;
1171
1172         stat = csa_register_callback(cal, flags, mb_update_handler, NULL, &cb_ext);
1173         if (stat != CSA_SUCCESS) {
1174                 backend_err_msg(b->frame, name, stat,
1175                         ((Props_pu *)c->properties_pu)->xm_error_pixmap);
1176                 return False;
1177         }
1178
1179         bd->cal_handle = cal;
1180         bd->user_access = user_access;
1181
1182         /* squirrel away data model version for later */
1183
1184         bd->version = get_data_version(cal);
1185
1186         return True;
1187 }
1188
1189 extern void
1190 mb_deregister_names(char *name, Calendar *c)
1191 {
1192         int             i;
1193         Browser         *b = (Browser *)c->browser;
1194         Props_pu        *p = (Props_pu *)c->properties_pu;
1195         BlistData       *bd;
1196         Browselist      *bl = (Browselist *)c->browselist;
1197         CSA_return_code stat;
1198
1199         i = 1;
1200         while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i))
1201                && strcmp(bd->name, name) != 0)
1202                 ++i;
1203         if (!bd)
1204                 return;
1205
1206         destroy_paint_cache(bd->cache, bd->cache_size);
1207         bd->cache = NULL;
1208         bd->cache_size = 0;
1209
1210         if (bd->cal_handle != c->my_cal_handle &&
1211             bd->cal_handle != c->cal_handle && bd->cal_handle) {
1212                 stat = csa_logoff(bd->cal_handle, NULL);
1213
1214
1215                 if (stat != CSA_SUCCESS) {
1216                         backend_err_msg(b->frame, bd->name, stat,
1217                                         p->xm_error_pixmap);
1218                 }
1219                 bd->cal_handle = '\0';
1220                 blist_clean(bl, False);
1221         }
1222 }
1223
1224 static void
1225 mb_box_notify(Widget widget, XtPointer client_data, XtPointer call_data)
1226 {
1227         XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
1228         Calendar *c = (Calendar *)client_data;
1229         int             i;
1230         char            *addr;
1231         Browser         *b;
1232         GEditor         *e;
1233         BlistData       *bd;
1234         Browselist      *bl;
1235         XmString        xmstr;
1236         char            name[BUFSIZ+5];
1237 #ifdef FNS
1238         int             rcode;
1239         char            *fns_name, buf[256];
1240 #endif
1241
1242         b = (Browser*)c->browser;
1243         bl = (Browselist*)c->browselist;
1244         e = (GEditor*)c->geditor;
1245
1246         i = 0;
1247         while (i < cbs->selected_item_count &&
1248                cbs->item_position != cbs->selected_item_positions[i])
1249                 ++i;
1250         b->add_to_array = (i < cbs->selected_item_count) ? True : False;
1251
1252         if ((bd = (BlistData *)CmDataListGetData(bl->blist_data,
1253                                                    cbs->item_position)) == NULL)
1254                 return;
1255         /* erase busy status if it was busy because it was deselected */
1256         if (!XmListPosSelected(b->browse_list, cbs->item_position)) {
1257                 sprintf(name, "  %s", bd->name);
1258                 xmstr = XmStringCreateLocalized(name);
1259                 XmListDeletePos(b->browse_list, cbs->item_position);
1260                 XmListAddItem(b->browse_list, xmstr, cbs->item_position);
1261                 XmStringFree(xmstr);
1262         }       
1263
1264 #ifdef FNS
1265         rcode = -1;
1266         if (cmfns_use_fns((Props *)c->properties)) {
1267                 /* Yes!  Try to use it */
1268                 rcode = cmfns_lookup_calendar(bd->name, buf, sizeof(buf));
1269         }
1270
1271         if (rcode > 0)
1272                 addr = buf;
1273         else 
1274 #endif
1275                 addr = bd->name;
1276
1277         _DtTurnOnHourGlass(b->frame);
1278         if (b->add_to_array) {
1279                 if (!register_names(addr, c)) {
1280                         XmListDeselectPos(b->browse_list, cbs->item_position);
1281                         _DtTurnOffHourGlass(b->frame);
1282                         return;
1283                 }
1284                 if (geditor_showing(e)) {
1285                         add_to_gaccess_list(addr, bd->cal_handle,
1286                                 bd->user_access, bd->version, e, True);
1287                         add_all_gappt(e);
1288                 }
1289                 mb_update_array(addr, c);
1290         } else {
1291                 /*
1292                  * Must update the array before we deregister names because we
1293                  * close the calendar handle when we deregister.
1294                  */
1295                 mb_update_array(addr, c);
1296                 mb_deregister_names(addr, c);
1297                 if (geditor_showing(e))
1298                         remove_from_gaccess_list(addr, e);
1299         }
1300         mb_refresh_canvas(b, c);
1301         _DtTurnOffHourGlass(b->frame);
1302 }
1303
1304 extern void
1305 mb_clear_selected_calendar(
1306         char            *name,
1307         Calendar        *c)
1308 {
1309         GEditor         *e = (GEditor*)c->geditor;
1310         Browser         *b = (Browser *)c->browser;
1311
1312         /*
1313          * Must update the array before we deregister names because we
1314          * close the calendar handle when we deregister.
1315          */
1316         b->add_to_array = False;
1317         mb_update_array(name, c);
1318         if (geditor_showing(e))
1319                 remove_from_gaccess_list(name, e);
1320         mb_deregister_names(name, c);
1321         mb_refresh_canvas(c->browser, c);
1322 }
1323
1324 extern void
1325 mb_init_canvas(Calendar *c)
1326 {
1327         Browser         *b = (Browser*)c->browser;
1328         Browselist      *bl = (Browselist *)c->browselist;
1329         BlistData       *bd;
1330         int             i;
1331
1332         b->add_to_array = True;
1333         gr_clear_area(b->xcontext, 0, 0, b->canvas_w, b->canvas_h);
1334         register_names(c->calname, c);
1335         mb_update_array(c->calname, c);
1336
1337         /*
1338          *  Search for the entry text in our list of calendar handles
1339          */
1340
1341         i = 1;
1342         while ((bd = (BlistData *)CmDataListGetData(bl->blist_data, i++))
1343                && strcmp(bd->name, c->calname) != 0);
1344
1345         if (!bd)
1346                 return;
1347
1348         XmListSelectPos(b->browse_list, i - 1, False);
1349 }
1350
1351
1352 extern void
1353 mb_init_datefield(Browser *b, Calendar *c)
1354 {
1355         char            *date;
1356         Props           *p = (Props *)c->properties;
1357         OrderingType    ot = get_int_prop(p, CP_DATEORDERING);
1358         SeparatorType   st = get_int_prop(p, CP_DATESEPARATOR);
1359
1360         date = XmTextGetString(b->datetext);
1361         if (!date || *date == '\0') {
1362                 date = get_date_from_widget(c->view->date, b->datetext, ot, st);
1363                 if (date != NULL)
1364                         XmTextSetString(b->datetext, date);
1365         }
1366 }
1367 static void
1368 mb_init_browchart(Browser *b, Calendar *c)
1369 {
1370         int             char_width, char_height, day_len, day_of_week;
1371         int             label_height, label_width;
1372         Props           *p = (Props *)c->properties;
1373         Dimension       canvas_width, canvas_height;
1374         XFontSetExtents fontextents;
1375  
1376         mb_init_datefield(b, c);
1377         XtVaGetValues(b->canvas,
1378                       XmNwidth, &canvas_width,
1379                       XmNheight, &canvas_height,
1380                       NULL);
1381         b->canvas_w = (int)canvas_width;
1382         b->canvas_h = (int)canvas_height;
1383         CalFontExtents(c->fonts->labelfont, &fontextents);
1384         char_height = fontextents.max_ink_extent.height;
1385         char_width = fontextents.max_ink_extent.width;
1386         label_height = char_height * 2;
1387         label_width = char_width + 2;
1388         b->chart_height =
1389                 b->canvas_h - (c->view->outside_margin * 2) - label_height - 5;
1390         b->chart_width =
1391                 b->canvas_w - (c->view->outside_margin * 2) - label_width;
1392         b->boxw = b->chart_width / 7;
1393         b->chart_width = b->boxw * 7;
1394
1395         day_len = get_int_prop(p, CP_DAYEND) - get_int_prop(p, CP_DAYBEGIN);
1396         b->boxh = b->chart_height / day_len;
1397
1398         /*
1399          * Make sure boxh is evenly divisable by BOX_SEG
1400          */
1401         b->boxh -= (b->boxh % BOX_SEG);
1402         b->chart_height = b->boxh * day_len;
1403         b->chart_x = c->view->outside_margin + label_width;
1404         b->chart_y = c->view->outside_margin + label_height + char_height;
1405 }       
1406
1407 extern void
1408 mb_draw_chartgrid(Browser *b, Calendar *c)
1409 {
1410         int             x, y;
1411         int             n;
1412         Props           *p = (Props*)c->properties;
1413         XFontSetExtents fontextents;
1414         int             char_height, char_width;
1415         char            label[5], buf[160];
1416         new_XContext    *xc = b->xcontext;
1417         int             dayy, dayweek;
1418         Tick            daytick;
1419         DisplayType     dt;
1420         int             nop;
1421         int             s_width;
1422  
1423  
1424         CalFontExtents(c->fonts->viewfont, &fontextents);
1425         char_height = fontextents.max_logical_extent.height;
1426         char_width = fontextents.max_logical_extent.width;
1427
1428         /*      Draw chart. It'll be filled in later.
1429                 Draw grid lines and hourly labels.      */
1430         x = b->chart_x;
1431         y = b->chart_y;
1432  
1433         /* clear header */
1434         gr_clear_area(xc, 0, 0, b->canvas_w, b->chart_y);
1435         label[0] = '\0';
1436
1437         /* draw hour labels */
1438         for (n = get_int_prop(p, CP_DAYBEGIN); n <= get_int_prop(p, CP_DAYEND); n++) {
1439         
1440                 dt = get_int_prop(p, CP_DEFAULTDISP);
1441                 if (dt == HOUR12)
1442                         sprintf(label, "%2d", n > 12 ? n - 12 : n);
1443                 else
1444                         sprintf(label, "%2d", n);
1445                 gr_text(xc, c->view->outside_margin-char_width, y+3,
1446                         c->fonts->viewfont, label, NULL);
1447                 gr_draw_line(xc, x, y, x + b->chart_width,
1448                          y, gr_solid, NULL);
1449                 y += b->boxh;
1450         }
1451  
1452         /*
1453          * Draw vertical lines and day labels
1454          */
1455         y = b->chart_y;
1456         dayy = y - char_height - 4;
1457         dayweek = dow(b->date);
1458         daytick = last_ndays(b->date, dayweek == 0 ? 6 : dayweek-1);
1459  
1460         /* draw month */
1461         format_date(b->begin_week_tick+1, get_int_prop(p, CP_DATEORDERING), buf, 0, 0, 0);
1462         gr_text(xc, c->view->outside_margin+4,
1463                  dayy-char_height-4, c->fonts->labelfont, buf, NULL);
1464  
1465         for (n = 0; n < 7; n++) {
1466                 if (daytick >= get_bot() && daytick < get_eot()) {
1467
1468                         CalTextExtents(c->fonts->viewfont, days3[n+1], strlen(days3[n+1]), &nop, &nop, &s_width, &nop);
1469
1470                         gr_text(xc, b->chart_x + (b->boxw * n) + ((b->boxw - s_width)/2),
1471                                 dayy, c->fonts->viewfont, days3[n+1], NULL);
1472
1473                         CalTextExtents(c->fonts->viewfont, numbers[dom(daytick)], strlen(numbers[dom(daytick)]), &nop, &nop, &s_width, &nop);
1474
1475                         gr_text(xc, b->chart_x + (b->boxw * n) + ((b->boxw - s_width)/2),
1476                                 y - char_height / 2, c->fonts->viewfont,
1477                                 numbers[dom(daytick)], NULL);
1478                 }
1479                 daytick += daysec;
1480                 gr_draw_line(xc, b->chart_x + (b->boxw * n),
1481                         y, b->chart_x + (b->boxw * n),
1482                         y + b->chart_height, gr_solid, NULL);
1483         }
1484  
1485         /*
1486          * Draw box around the whole thing.
1487          */
1488         gr_draw_box(xc, b->chart_x, b->chart_y, b->chart_width, b->chart_height, NULL);
1489         gr_draw_box(xc, b->chart_x-1, b->chart_y-1, b->chart_width+2, b->chart_height+2, NULL);
1490 }
1491
1492 extern void
1493 mb_draw_appts(Browser *b, int start, int end, Calendar *c)
1494 {
1495         int             x, y, h, i, end_of_day;
1496         Boolean         outofbounds = False;
1497         Colormap        cms;
1498
1499         if (next_ndays(b->date, 1) > get_eot())
1500                 outofbounds = True;
1501         XtVaGetValues(b->canvas, XmNcolormap, &cms, NULL);
1502
1503         h = (b->boxh/BOX_SEG);
1504         end_of_day = (b->segs_in_array / 7);
1505  
1506         y = b->chart_y + (start % end_of_day) * h;
1507         x = b->chart_x + (start/end_of_day * b->boxw);
1508  
1509         i = start;
1510         while (i < end) {
1511                 if (b->multi_array[i] <= 0) {
1512                         gr_clear_area(b->xcontext, x, y, b->boxw, h);
1513                         y += h;
1514                         i++;
1515                 }
1516                 else if (b->multi_array[i] == 1) {
1517                         /* batch up for one repaint */
1518                         if ( ((i+1) < b->segs_in_array)
1519                                  && b->multi_array[i+1] == 1 &&
1520                                 ( ((i+1) % end_of_day) != 0)) {
1521                                 h += (b->boxh/BOX_SEG);
1522                                 if (++i < end)
1523                                         continue;
1524                         }
1525                         if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
1526                                 gr_make_gray(b->xcontext, x, y, b->boxw, h, 25);
1527                         else
1528                                 gr_make_grayshade(b->xcontext, x, y, b->boxw, h,
1529                                                         LIGHTGREY);
1530                         y += h;
1531                         h = (b->boxh/BOX_SEG);
1532                         i++;
1533                 }
1534                 else if (b->multi_array[i] == 2) {
1535                         /* batch up for one repaint */
1536                         if ( ((i+1) < b->segs_in_array)
1537                                  && b->multi_array[i+1] == 2 &&
1538                                 ( ((i+1) % end_of_day) != 0) ) {
1539                                 h += (b->boxh/BOX_SEG);
1540                                 if (++i < end)
1541                                         continue;
1542                         }
1543                         if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
1544                                 gr_make_gray(b->xcontext, x, y, b->boxw, h, 50);
1545                         else
1546                                 gr_make_rgbcolor(b->xcontext, cms, x, y,
1547                                                  b->boxw, h, MIDGREY, MIDGREY,
1548                                                  MIDGREY);
1549                         y += h;
1550                         h = (b->boxh/BOX_SEG);
1551                         i++;
1552                 }
1553                 else if (b->multi_array[i] >= 3) {
1554                         /* batch up for one repaint */
1555                         if ( ((i+1) < b->segs_in_array)
1556                                 && b->multi_array[i+1] >= 3 &&
1557                                 ( ((i+1) % end_of_day) != 0) ) {
1558                                 h += (b->boxh/BOX_SEG);
1559                                 if (++i < end)
1560                                         continue;
1561                         }
1562                         if ((c->xcontext->screen_depth < 8) || FAKE_MONOCHROME)
1563                                 gr_make_gray(b->xcontext, x, y, b->boxw, h, 75);
1564                         else
1565                                 gr_make_rgbcolor(b->xcontext, cms, x, y,
1566                                                  b->boxw, h, DIMGREY, DIMGREY,
1567                                                  DIMGREY);
1568                         y += h;
1569                         h = (b->boxh/BOX_SEG);
1570                         i++;
1571                 }
1572                 if (i != 0 && ((i % end_of_day) == 0)) {
1573                         x += b->boxw;
1574                         y = b->chart_y;
1575                         h = (b->boxh/BOX_SEG);
1576                 }
1577         if (outofbounds && i > 4)
1578                 break;
1579         }
1580
1581         browser_select(c, b, NULL);
1582 }
1583
1584 extern void
1585 mb_refresh_canvas(Browser *b, Calendar *c)
1586 {
1587         mb_draw_appts(b, 0, b->segs_in_array, c);
1588         mb_draw_chartgrid(b, c);
1589         mb_display_footermess(b, c);
1590 }
1591
1592 void
1593 mb_resize_proc(Widget w, XtPointer client_data, XtPointer call)
1594 {
1595         Dimension width, height;
1596         Calendar *c = (Calendar *)client_data;
1597         Browser *b;
1598
1599         XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
1600         b = (Browser*)c->browser;
1601         gr_clear_area(b->xcontext, 0, 0, width, height);
1602         mb_init_browchart(b, c);
1603         mb_refresh_canvas(b, c);
1604 }
1605
1606 void
1607 mb_refigure_chart(Calendar *c) {
1608         mb_resize_proc(((Browser *)c->browser)->canvas, (XtPointer)c, NULL);
1609 }
1610
1611 extern void
1612 browser_reset_list(Calendar *c) {
1613         int             i;
1614         Browser         *b = (Browser *)c->browser;
1615         BlistData       *bd;
1616         Browselist      *bl = (Browselist *)c->browselist;
1617         XmStringTable   list_selected_items, selected_items;
1618         int             selected_items_count;
1619
1620         XtVaGetValues(b->browse_list,
1621                 XmNselectedItemCount,   &selected_items_count,
1622                 XmNselectedItems,       &list_selected_items,
1623                 NULL);
1624
1625         selected_items = (XmStringTable)calloc(selected_items_count, 
1626                                                         sizeof(XmStringTable));
1627         for (i = 0; i < selected_items_count; i++)
1628                 selected_items[i] = XmStringCopy(list_selected_items[i]);
1629
1630         XtVaSetValues(b->upper_form, XmNresizePolicy, XmRESIZE_NONE, NULL);
1631         /*
1632          * When a user removes a calendar from the menu we remove it
1633          * from the multi-browser.  If the calendar happens to be selected
1634          * in the multi-browser then we must deselect it and clean up
1635          * the browser.  That's what this first loops does.
1636          */
1637         for (i = 1; i <= bl->blist_data->count; i++) {
1638                 bd = (BlistData *)CmDataListGetData(bl->blist_data, i);
1639                 if (bd && bd->tag != BLIST_ACTIVE) {
1640                         mb_clear_selected_calendar(bd->name, c);
1641                         /* We need to reset this to one because the blist_data
1642                          * has changed which may cause us to miss an item.
1643                          */
1644                         i = 1;
1645                 }
1646         }
1647
1648         XmListDeleteAllItems(b->browse_list);
1649         for (i = 1; i <= bl->blist_data->count; i++) {
1650                 bd = (BlistData *)CmDataListGetData(bl->blist_data, i);
1651                 if (bd && bd->name) {
1652                         char            buf[BUFSIZ + 5];
1653                         XmString        xmstr;
1654
1655                         sprintf(buf, "  %s", bd->name); 
1656                         xmstr = XmStringCreateLocalized(buf);
1657                         if (!XmListItemExists(b->browse_list, xmstr))
1658                                 XmListAddItem(b->browse_list, xmstr, 0);
1659                         XmStringFree(xmstr);
1660                 }
1661         }
1662         XtVaSetValues(b->upper_form, XmNresizePolicy, XmRESIZE_ANY, NULL);
1663         
1664         /*
1665          * Reselect the items that were selected before we changed the
1666          * contents of the mb.
1667          */
1668         for (i = 0; i < selected_items_count; i++) {
1669                 int     *pos_list, 
1670                          pos_cnt;
1671
1672                 if (XmListGetMatchPos(b->browse_list, selected_items[i],
1673                                       &pos_list, &pos_cnt))
1674                         XmListSelectPos(b->browse_list, pos_list[0], False);
1675                 XmStringFree(selected_items[i]);
1676         }
1677
1678         if (selected_items)
1679                 free(selected_items);
1680 }
1681
1682 extern void
1683 init_browser(Calendar *c)
1684 {
1685         pr_pos  xy;
1686         Browser *b = (Browser*)c->browser;
1687  
1688         browser_reset_list(c);
1689         b->row_sel = b->col_sel = 0;
1690         mb_init_browchart(b, c);
1691         mb_init_canvas(c);
1692         mb_refresh_canvas(b, c);
1693         xy.x = dow(b->date) - 1;
1694         xy.y = 0;
1695         browser_select(c, b, &xy);
1696 }
1697
1698 static void
1699 cancel_cb(Widget w, XtPointer client, XtPointer call)
1700 {
1701         Calendar *c = (Calendar *)client;
1702         Browser *b = (Browser *)c->browser;
1703
1704         XtPopdown(b->frame);
1705
1706         XtDestroyWidget(b->frame);
1707         XtFree(b->multi_array); 
1708         XtFree(c->browser); c->browser = NULL;
1709 }
1710
1711 static void
1712 popup_cb(Widget w, XtPointer client, XtPointer call)
1713 {
1714         Calendar *c = (Calendar *)client;
1715         Browser *b = (Browser *)c->browser;
1716         Position x, y;
1717
1718         XtVaGetValues(c->frame, XmNx, &x, XmNy, &y, NULL);
1719         XtVaSetValues(b->frame, XmNx, x+100, XmNy, y+100, NULL);
1720 }
1721
1722 /*
1723  * This is the CSA_callback called from the CSA library when
1724  * an update occurs on a calendar to which we are logged on,
1725  * and have registered interest.  Registered in register_names.
1726  * When calendar is logged off, any registered callbacks for it
1727  * are destroyed automagically.
1728  */
1729 static void
1730 mb_update_handler(CSA_session_handle cal, CSA_flags reason,
1731                CSA_buffer call_data, CSA_buffer client_data, CSA_extension *ext)
1732 {
1733         Calendar        *c = calendar;
1734         Browser         *b = (Browser *)c->browser;
1735
1736         /* sync whatever needs sync'ing */
1737         if (b) {
1738                 br_display(c);
1739                 if (geditor_showing((GEditor *)c->geditor))
1740                         add_all_gappt((GEditor *)c->geditor);
1741         }
1742  
1743 }
1744