Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / editor.c
1 /* $TOG: editor.c /main/13 1999/07/01 11:44:34 mgreess $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <EUSCompat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <Xm/Xm.h>
15 #include <Xm/DialogS.h>
16 #include <Xm/Form.h>
17 #include <Xm/List.h>
18 #include <Xm/Frame.h>
19 #include <Xm/PushB.h>
20 #include <Xm/RowColumn.h>
21 #include <Xm/ScrolledW.h>
22 #include <Xm/SeparatoG.h>
23 #include <Xm/Text.h>
24 #include <Xm/ToggleBG.h>
25 #include <Xm/LabelG.h>
26 #include <Xm/DragDrop.h>
27 #include <Xm/Screen.h>
28 #include <Dt/HourGlass.h>
29 #include <Dt/Dt.h>
30 #include <Dt/Dnd.h>
31 #include <Dt/Icon.h>
32 #include "editor.h"
33 #include "calendar.h"
34 #include "datefield.h"
35 #include "deskset.h"
36 #include "getdate.h"
37 #include "format.h"
38 #include "timeops.h"
39 #include "props.h"
40 #include "props_pu.h"
41 #include "group_editor.h"
42 #include "browser.h"
43 #include "util.h"
44 #include "dnd.h"
45 #include "help.h"
46 #ifdef SVR4
47 #include <sys/param.h>
48 #endif /* SVR4 */
49
50 static void e_build_expand(Editor *);
51 static void clear_flag_on_modify(Widget, XtPointer, XtPointer);
52
53 /* Absolute value macro */
54 #ifndef ABS
55 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
56 #endif
57
58 static void set_editor_msg_defaults();
59
60 /*******************************************************************************
61 **
62 **  Functions static to editor.c
63 **
64 *******************************************************************************/
65
66 static void
67 clear_flag_on_modify(Widget w, XtPointer uData, XtPointer cbData)
68 {
69   int *flagP = (int *)uData;
70
71   *flagP = 0;
72 }
73
74 /*
75 **  This function will take appointment values and stuff them into a form.
76 */
77 static void
78 appt_to_form(Editor *e, CSA_entry_handle a) {
79         char                    buf[MAXNAMELEN];
80         CSA_return_code         status;
81         Dtcm_appointment        *appt;
82
83         if (!e->reminders.bfpm_form_mgr) {
84                 e_build_expand(e);
85                 set_rfp_defaults(&e->rfp);
86                 set_reminders_defaults(&e->reminders);
87         }
88
89         if (!dssw_appt_to_form(&e->dssw, a))
90                 return;
91         e->dsswFlags = 0;
92         if (!rfp_appt_to_form(&e->rfp, a))
93                 return;
94         e->rfpFlags = 0;
95         if (!reminders_appt_to_form(&e->reminders, a))
96                 return;
97
98         appt = allocate_appt_struct(appt_read, 
99                                         e->cal->general->version,
100                                         CSA_ENTRY_ATTR_ORGANIZER_I, 
101                                         NULL);
102         status = query_appt_struct(e->cal->cal_handle,a, appt);
103         backend_err_msg(e->frame, e->cal->view->current_calendar, status,
104                         ((Props_pu *)e->cal->properties_pu)->xm_error_pixmap);
105         if (status != CSA_SUCCESS) {
106                 free_appt_struct(&appt);
107                 return;
108         }
109         sprintf(buf, "%s:  %s", catgets(e->cal->DT_catd, 1, 251, "Author"),
110                 appt->author->value->item.calendar_user_value->user_name);
111         set_message(e->message_text, buf);
112         free_appt_struct(&appt);
113 }
114
115 /*
116 **  List selection procedure will get the correct appointment, then call
117 **  appt_to_form to load it into the UI.
118 */
119 static void
120 e_list_select_proc(Widget w, XtPointer client_data, XtPointer data) {
121         CSA_entry_handle                a;
122         Editor                  *e = (Editor *)client_data;
123         XmListCallbackStruct    *cbs = (XmListCallbackStruct *) data;
124
125         if (a = editor_nth_appt(e, cbs->item_position - 1))
126                 appt_to_form(e, a);
127
128         XtSetSensitive(e->delete_button, True);
129         XtSetSensitive(e->change_button, True);
130 }
131 /*
132 **  Quit handler for the editor and the editor view popup
133 */
134 static void
135 e_quit_handler(Widget w, XtPointer cdata, XtPointer data) {
136         Editor *e = (Editor *)cdata;
137         Widget popMeDown;
138
139         if (w == e->frame) {
140                 editor_clean_up(e);
141                 e->editor_is_up = False;
142                 popMeDown = e->base_form_mgr;
143         } else if (w == e->view_frame)
144         {
145                 e->editor_view_is_up = False;
146                 popMeDown = e->view_form;
147         }
148
149         XtUnmanageChild(popMeDown);
150 }
151
152
153 static void
154 e_view_cancel_cb(
155         Widget  widget,
156         XtPointer client_data,
157         XmPushButtonCallbackStruct *cbs)
158 {
159         Editor          *e = (Editor *)client_data;
160
161         XtUnmanageChild(e->view_form);
162 }
163
164 /*
165 **  Build the popup to display, in list fashion, the appts for a given period.
166 */
167 static void
168 e_build_view_popup(Editor *e) {
169         int             ac = 0;
170         Arg             args[15];
171         XmString        xmstr;
172         Calendar        *c = e->cal;
173         Widget          separator;
174         char            *title;
175
176         /*
177         **  Dialog shell and stuff
178         */
179         title = XtNewString(catgets(c->DT_catd, 1, 1086, 
180                                     "Calendar : Appointment List"));
181         e->view_frame = XtVaCreatePopupShell("appt_list",
182                 xmDialogShellWidgetClass,       e->cal->frame,
183                 XmNtitle,                       title,
184                 XmNdeleteResponse,              XmDO_NOTHING,
185                 XmNautoUnmanage,                False,
186                 XmNallowShellResize,            True,
187                 NULL);
188         XtFree(title);
189         setup_quit_handler(e->view_frame, e_quit_handler, (caddr_t)e);
190
191         e->view_form = XtVaCreateWidget("apptform",
192                         xmFormWidgetClass,      e->view_frame,
193                         XmNfractionBase,        2,
194                         XmNmarginWidth,         2,
195                         XmNautoUnmanage,        False,
196                         NULL);
197
198         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 680, "Close"));
199         e->view_cancel_button = XtVaCreateWidget("cancel",
200                         xmPushButtonWidgetClass,        e->view_form,
201                         XmNlabelString,                 xmstr,
202                         XmNleftAttachment,              XmATTACH_POSITION,
203                         XmNleftPosition,                0,
204                         XmNrightAttachment,             XmATTACH_POSITION,
205                         XmNrightPosition,               1,
206                         XmNbottomAttachment,            XmATTACH_FORM,
207                         XmNleftOffset,                  10,
208                         NULL);
209         XmStringFree(xmstr);
210
211         XtAddCallback(e->view_cancel_button, XmNactivateCallback, (XtCallbackProc) e_view_cancel_cb, e);
212
213         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
214         e->view_help_button = XtVaCreateWidget("help",
215                         xmPushButtonWidgetClass,        e->view_form,
216                         XmNlabelString,                 xmstr,
217                         XmNleftAttachment,              XmATTACH_POSITION,
218                         XmNleftPosition,                1,
219                         XmNrightAttachment,             XmATTACH_POSITION,
220                         XmNrightPosition,               2,
221                         XmNbottomAttachment,            XmATTACH_FORM,
222                         XmNrightOffset,                 10,
223                         NULL);
224         XmStringFree(xmstr);
225
226         separator = XtVaCreateWidget("separator",
227                 xmSeparatorGadgetClass,
228                 e->view_form,
229                 XmNleftAttachment,      XmATTACH_FORM,
230                 XmNrightAttachment,     XmATTACH_FORM,
231                 XmNbottomAttachment,    XmATTACH_WIDGET,
232                 XmNbottomWidget,        e->view_cancel_button,
233                 XmNbottomOffset,        5,
234                 NULL);
235
236         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 703, "context"));
237         e->view_list_label= XtVaCreateWidget("type_label",
238                 xmLabelGadgetClass,     e->view_form,
239                 XmNtopAttachment,       XmATTACH_FORM,
240                 XmNleftAttachment,      XmATTACH_FORM,
241                 XmNleftOffset,          5,
242                 XmNtopOffset,           5,
243                 XmNlabelString,         xmstr,
244                 NULL);
245         XmStringFree(xmstr);
246
247
248         ac = 0;
249         XtSetArg(args[ac], XmNwidth, 300); ac++;
250         XtSetArg(args[ac], XmNheight, 200); ac++;
251         XtSetArg(args[ac], XmNscrolledWindowMarginHeight, 5); ac++;
252         XtSetArg(args[ac], XmNscrolledWindowMarginWidth, 5); ac++;
253         XtSetArg(args[ac], XmNlistSpacing, 5); ac++;
254         XtSetArg(args[ac], XmNlistSizePolicy, XmCONSTANT); ++ac;
255         XtSetArg(args[ac], XmNrightAttachment, XmATTACH_FORM); ++ac;
256         XtSetArg(args[ac], XmNrightOffset, 2); ++ac;
257         XtSetArg(args[ac], XmNleftAttachment, XmATTACH_FORM); ++ac;
258         XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ++ac;
259         XtSetArg(args[ac], XmNtopWidget, e->view_list_label); ++ac;
260         XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ++ac;
261         XtSetArg(args[ac], XmNbottomWidget, separator); ++ac;
262         XtSetArg(args[ac], XmNbottomOffset, 5); ++ac;
263         XtSetArg(args[ac], XmNdoubleClickInterval, 5); ++ac;
264         e->view_list = XmCreateScrolledList(e->view_form, "view_list",
265                                             args, ac);
266
267         XtAddCallback(e->view_help_button, XmNactivateCallback, 
268                 (XtCallbackProc)help_cb, APPT_LIST_HELP_BUTTON);
269         XtAddCallback(e->view_form, XmNhelpCallback, 
270                 (XtCallbackProc)help_cb, (XtPointer) APPT_LIST_HELP_BUTTON);
271
272         XtManageChild(e->view_list);
273         ManageChildren(e->view_form);
274         XtManageChild(e->view_form);
275         e->editor_view_is_up = False;
276 }
277
278 /*
279 **  This function creates the expando stuff on a form manager.
280 */
281 static void
282 e_build_expand(
283         Editor          *e)
284 {
285         Props           *p = (Props *)e->cal->properties;
286
287         /*
288         **  Build the rfp "widget"
289         */
290         e->rfpFlags = 0;
291         build_rfp(&e->rfp, e->cal, e->base_form_mgr);
292         XtVaSetValues(e->rfp.rfp_form_mgr,
293                 XmNleftAttachment,      XmATTACH_FORM,
294                 XmNleftOffset,          3,
295                 XmNtopAttachment,       XmATTACH_WIDGET,
296                 XmNtopWidget,           e->separator1,
297                 NULL);
298         ManageChildren(e->rfp.rfp_form_mgr);
299
300         XtAddCallback(e->rfp.repeat_menu, XmNselectionCallback,
301                       clear_flag_on_modify, (XtPointer)&e->rfpFlags);
302
303         /*
304         **  Call the build_reminders function to build that widget
305         */
306         build_reminders(&e->reminders, e->cal, e->base_form_mgr);
307         XtVaSetValues(e->reminders.bfpm_form_mgr,
308                 XmNleftAttachment,      XmATTACH_WIDGET,
309                 XmNleftWidget,          e->rfp.rfp_form_mgr,
310                 XmNrightOffset,         3,
311                 XmNtopAttachment,       XmATTACH_WIDGET,
312                 XmNtopWidget,           e->separator1,
313                 NULL);
314         ManageChildren(e->reminders.bfpm_form_mgr);
315 }
316
317 /*
318 **  Button action procedures manage and unmanage the "extra" stuff in the UI to
319 **  make it visible and invisible to the user.
320 */
321 static void
322 e_expand_ui_proc(Widget w, XtPointer client_data, XtPointer data) {
323         Editor          *e = (Editor *)client_data;
324         Props_pu        *p = (Props_pu *)e->cal->properties_pu;
325         XmString        xmstr;
326         Dimension       h, height, width;
327         static Boolean  expand_state_closed = True;
328
329         XtVaGetValues(e->appt_list_sw, 
330                         XmNheight,      &height, 
331                         XmNwidth,       &width, 
332                         NULL);
333
334         if (expand_state_closed) {
335                 Widget  children[2];
336
337                 if (!e->reminders.bfpm_form_mgr) {
338                         e_build_expand(e);
339                         set_rfp_defaults(&e->rfp);
340                         set_reminders_defaults(&e->reminders);
341                 }
342
343                 XtRealizeWidget(e->rfp.rfp_form_mgr);
344                 XtRealizeWidget(e->reminders.bfpm_form_mgr);
345
346                 xmstr = XmStringCreateLocalized(catgets(e->cal->DT_catd, 1, 625,
347                                                         "Less"));
348                 XtVaSetValues(e->expand_ui_button, XmNlabelString, xmstr,
349                               NULL);
350                 XmStringFree(xmstr);
351
352                 XtVaGetValues(e->reminders.bfpm_form_mgr, XmNheight, &h, NULL);
353                 XtVaSetValues(e->separator1, XmNbottomOffset, h + 10, NULL);
354
355                 children[0] = e->rfp.rfp_form_mgr;
356                 children[1] = e->reminders.bfpm_form_mgr;
357
358                 XtManageChildren(children, 2);
359
360                 expand_state_closed = False;
361         } else {
362                 xmstr = XmStringCreateLocalized(catgets(e->cal->DT_catd, 1, 626,
363                                                         "More"));
364                 XtVaSetValues(e->expand_ui_button, XmNlabelString, xmstr,
365                               NULL);
366                 XmStringFree(xmstr);
367                 XtUnmanageChild(e->rfp.rfp_form_mgr);
368                 XtUnmanageChild(e->reminders.bfpm_form_mgr);
369                 XtVaSetValues(e->separator1, XmNbottomOffset, 0, NULL);
370                 expand_state_closed = True;
371         }
372         XtVaSetValues(e->appt_list_sw, 
373                 XmNheight, height, 
374                 XmNwidth, width, 
375                 NULL);
376 }
377
378
379 /*
380 **  This function will consume form values and stuff them into an appointment.
381 */
382 static Dtcm_appointment*
383 form_to_appt(Editor *e) {
384         boolean_t               all_ok;
385         Dtcm_appointment        *a;
386
387         /* This code needs to conditionally decide whether to write out
388            the repeating event specification as an old style set of
389            specifications, or a new style recurrence rule.  In the case
390            of data versions 1-3, it needs to be the old style.  In the
391            case of version 4 it needs to be the new style. */
392
393         a = allocate_appt_struct(appt_write, e->cal->general->version, NULL);
394
395         all_ok = dssw_form_to_appt(&e->dssw, a, e->cal->view->current_calendar,
396                                    e->cal->view->date);
397         if (all_ok)
398                 all_ok = rfp_form_to_appt(&e->rfp, a,
399                                           e->cal->view->current_calendar);
400         if (all_ok)
401                 all_ok = reminders_form_to_appt(&e->reminders, a, e->cal->view->current_calendar);
402
403         if (!all_ok) {
404                 free_appt_struct(&a);
405                 return NULL;
406         }
407         a->type->value->item.sint32_value = CSA_TYPE_EVENT;
408         a->subtype->value->item.string_value = strdup(CSA_SUBTYPE_APPOINTMENT);
409         a->state->value->item.sint32_value = CSA_X_DT_STATUS_ACTIVE;
410
411         return a;
412 }
413
414 /*
415 **  Action procedures
416 */
417 static void
418 e_insert_proc(Widget w, XtPointer client_data, XtPointer data) {
419         Editor                  *e = (Editor *)client_data;
420         CSA_entry_handle        new_a = 0;
421         Dtcm_appointment        *a;
422         Calendar                *c = e->cal;
423
424         if (strcmp(c->calname, c->view->current_calendar) != 0) {
425                 char buf[BUFSIZ], buf2[BUFSIZ];
426                 int answer = 0;
427                 char *title;
428                 char *ident;
429                 /*
430                  * Make sure user really meant to insert appointment
431                  * into somebody elses calendar.
432                  */
433                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 210, "The appointment will be scheduled in the calendar\nyou are currently browsing.  Do you still want to schedule it?"));
434                 sprintf(buf2, "%s %s", catgets(c->DT_catd, 1, 211, "Schedule in"),
435                         c->view->current_calendar);
436                 title = XtNewString(catgets(c->DT_catd, 1, 212,
437                                             "Calendar : Schedule Appointment"));
438                 ident = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
439                 answer = dialog_popup(e->frame,
440                         DIALOG_TITLE, title,
441                         DIALOG_TEXT, buf,
442                         BUTTON_IDENT, 1, ident,
443                         BUTTON_IDENT, 2, buf2,
444                         NULL);
445                 XtFree(ident);
446                 XtFree(title);
447                 if (answer == 1)
448                         return;
449         }
450
451         _DtTurnOnHourGlass(e->frame);
452         if ((a = form_to_appt(e)) != NULL) {
453                 if ((editor_insert(a, &new_a, e->cal)) == True)
454                         csa_free((CSA_buffer)new_a);
455                 free_appt_struct(&a);
456         }
457         _DtTurnOffHourGlass(e->frame);
458 }
459
460 static void
461 e_delete_proc(Widget w, XtPointer client_data, XtPointer data) {
462         int             *item_list = NULL, item_cnt = 0;
463         CSA_entry_handle        a;
464         Editor          *e = (Editor *)client_data;
465         Calendar        *c = e->cal;
466         Props_pu        *p = (Props_pu *)e->cal->properties_pu;
467         static int      answer;
468
469         if (strcmp(c->calname, c->view->current_calendar) != 0) {
470                 char buf[BUFSIZ], buf2[BUFSIZ];
471                 char *title;
472                 char *ident;
473                 /*
474                  * Make sure user really meant to delete appointment
475                  * from somebody elses calendar.
476                  */
477                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 1004, "This appointment is in a calendar owned by someone else.\nDo you want to delete it anyway ?"));
478                 sprintf(buf2, "%s %s", catgets(c->DT_catd, 1, 1005, "Delete from"),
479                         c->view->current_calendar);
480                 title = XtNewString(catgets(c->DT_catd, 1, 252,
481                                 "Calendar : Appointment Editor - Delete"));
482                 ident = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
483                 answer = dialog_popup(e->frame,
484                         DIALOG_TITLE, title,
485                         DIALOG_TEXT, buf,
486                         BUTTON_IDENT, 1, ident,
487                         BUTTON_IDENT, 2, buf2,
488                         NULL);
489                 XtFree(ident);
490                 XtFree(title);
491                 if (answer == 1)
492                         return;
493         }
494
495         _DtTurnOnHourGlass(e->frame);
496         if (!XmListGetSelectedPos(e->appt_list, &item_list, &item_cnt)) {
497                 char *title = XtNewString(catgets(c->DT_catd, 1, 252,
498                                 "Calendar : Appointment Editor - Delete"));
499                 char *text = XtNewString(catgets(c->DT_catd, 1, 253,
500                                 "Select an appointment and DELETE again."));
501                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
502                 answer = dialog_popup(e->frame,
503                         DIALOG_TITLE, title,
504                         DIALOG_TEXT, text,
505                         BUTTON_IDENT, 1, ident,
506                         DIALOG_IMAGE, p->xm_error_pixmap,
507                         NULL);
508                 XtFree(ident);
509                 XtFree(text);
510                 XtFree(title);
511                 _DtTurnOffHourGlass(e->frame);
512                 return;
513         } 
514
515         if (!(a = editor_nth_appt(e, item_list[0] - 1))) {
516                 char *title = XtNewString(catgets(c->DT_catd, 1, 252,
517                                 "Calendar : Appointment Editor - Delete"));
518                 char *text = XtNewString(catgets(c->DT_catd, 1, 256,
519                                 "Internal error selecting appointment.\nAppointment was not deleted."));
520                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
521                 answer = dialog_popup(e->frame,
522                         DIALOG_TITLE, title,
523                         DIALOG_TEXT, text,
524                         BUTTON_IDENT, 1, ident,
525                         BUTTON_HELP, RESELECT_ERROR_HELP,
526                         DIALOG_IMAGE, p->xm_error_pixmap,
527                         NULL);
528                 XtFree(ident);
529                 XtFree(text);
530                 XtFree(title);
531                 XtFree((XtPointer)item_list);
532                 _DtTurnOffHourGlass(e->frame);
533                 return;
534         }
535         XtFree((XtPointer)item_list);
536
537         editor_delete(a, e->cal);
538         _DtTurnOffHourGlass(e->frame);
539 }
540
541 static void
542 e_change_proc(Widget w, XtPointer client_data, XtPointer data) {
543         int                     *item_list = NULL, item_cnt = 0;
544         Editor                  *e = (Editor *)client_data;
545         Calendar                *c = e->cal;
546         CSA_entry_handle        old_a, updated_a;
547         Props_pu                *p = (Props_pu *)e->cal->properties_pu;
548         static int              answer;
549         Dtcm_appointment        *new_a;
550
551         if (strcmp(c->calname, c->view->current_calendar) != 0) {
552                 char buf[BUFSIZ], buf2[BUFSIZ];
553                 char *title = XtNewString(catgets(c->DT_catd, 1, 258,
554                                 "Calendar : Appointment Editor - Change"));
555                 char *ident = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
556                 /*
557                  * Make sure user really meant to insert appointment
558                  * into somebody elses calendar.
559                  */
560                 sprintf(buf, "%s", catgets(c->DT_catd, 1, 1003, "This appointment is in a calendar owned by someone else.\nDo you want to change it anyway ?"));
561                 sprintf(buf2, "%s %s", catgets(c->DT_catd, 1, 1006, "Change in"),
562                         c->view->current_calendar);
563                 answer = dialog_popup(e->frame,
564                         DIALOG_TITLE, title,
565                         DIALOG_TEXT, buf,
566                         BUTTON_IDENT, 1, ident,
567                         BUTTON_IDENT, 2, buf2,
568                         NULL);
569                 XtFree(ident);
570                 XtFree(title);
571                 if (answer == 1)
572                         return;
573         }
574
575         _DtTurnOnHourGlass(e->frame);
576         if (!XmListGetSelectedPos(e->appt_list, &item_list, &item_cnt)) {
577                 char *title = XtNewString(catgets(c->DT_catd, 1, 258,
578                                 "Calendar : Appointment Editor - Change"));
579                 char *text = XtNewString(catgets(c->DT_catd, 1, 259,
580                                 "Select an appointment and CHANGE again."));
581                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
582                 answer = dialog_popup(e->frame,
583                         DIALOG_TITLE, title,
584                         DIALOG_TEXT, text,
585                         BUTTON_IDENT, 1, ident,
586                         DIALOG_IMAGE, p->xm_error_pixmap,
587                         NULL);
588                 XtFree(ident);
589                 XtFree(text);
590                 XtFree(title);
591                 _DtTurnOffHourGlass(e->frame);
592                 return;
593         } 
594
595         if (!(old_a = editor_nth_appt(e, item_list[0] - 1))) {
596                 char *title = XtNewString(catgets(c->DT_catd, 1, 1075,
597                                 "Calendar : Error - Change Appointment"));
598                 char *text = XtNewString(catgets(c->DT_catd, 1, 1007,
599                                 "Internal error selecting appointment.\nAppointment was not changed."));
600                 char *ident = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
601                 answer = dialog_popup(e->frame,
602                         DIALOG_TITLE, title,
603                         DIALOG_TEXT, text,
604                         BUTTON_IDENT, 1, ident,
605                         DIALOG_IMAGE, p->xm_error_pixmap,
606                         NULL);
607                 XtFree(ident);
608                 XtFree(text);
609                 XtFree(title);
610                 XtFree((XtPointer)item_list);
611                 _DtTurnOffHourGlass(e->frame);
612                 return;
613         }
614         XtFree((XtPointer)item_list);
615
616         if ((new_a = form_to_appt(e)) == NULL) {
617                 _DtTurnOffHourGlass(e->frame);
618                 return;
619         }
620
621         if (editor_change(new_a, old_a, &updated_a, e->cal))
622                 csa_free((CSA_buffer)updated_a);
623
624         free_appt_struct(&new_a);
625         _DtTurnOffHourGlass(e->frame);
626 }
627
628 static void
629 e_clear_proc(Widget w, XtPointer client_data, XtPointer data) {
630         Editor *e = (Editor *)client_data;
631
632         set_editor_defaults(e, 0, 0, False);
633         add_all_appt(e);
634 }
635
636 static void
637 e_close_proc(Widget w, XtPointer client_data, XtPointer data) {
638         Editor *e = (Editor *)client_data;
639
640         XtUnmanageChild(e->base_form_mgr);
641         e->editor_is_up = False;
642 }
643
644 /*
645  * dragMotionHandler
646  *
647  * Determine if the pointer has moved beyond the drag threshold while button 1
648  * was being held down.
649  */
650 void
651 FormApptDragMotionHandler(
652         Widget          dragInitiator,
653         XtPointer       clientData,
654         XEvent         *event)
655 {
656         int             diffX, diffY;
657         Calendar        *c = (Calendar *) clientData;
658         Editor          *e = (Editor *) c->editor;
659         Dimension       source_height, source_width;
660         Position        source_x, source_y;
661  
662         if (!e->doing_drag) {
663
664                 /* check to see if the iniital value was within the 
665                    bounds for the drag source icon. */
666
667                 XtVaGetValues(e->drag_source, 
668                                 XmNx, &source_x,
669                                 XmNy, &source_y,
670                                 XmNheight, &source_height,
671                                 XmNwidth, &source_width,
672                                 NULL);
673
674                 if ((event->xmotion.x < source_x) ||
675                     (event->xmotion.y < source_y) ||
676                     (event->xmotion.x > (int) (source_x + source_width)) ||
677                     (event->xmotion.y > (int) (source_y + source_height)))
678                         return;
679
680                 /*
681                  * If the drag is just starting, set initial button down coords
682                  */
683                 if (e->initialX == -1 && e->initialY == -1) {
684                         e->initialX = event->xmotion.x;
685                         e->initialY = event->xmotion.y;
686                 }
687                 /*
688                  * Find out how far pointer has moved since button press
689                  */
690                 diffX = e->initialX - event->xmotion.x;
691                 diffY = e->initialY - event->xmotion.y;
692  
693                 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
694                     (ABS(diffY) >= DRAG_THRESHOLD)) {
695                         e->doing_drag = True;
696                         ApptDragStart(dragInitiator, event, c, SingleEditorIcon);
697                         e->initialX = -1;
698                         e->initialY = -1;
699                 }
700         }
701 }
702
703 extern void
704 e_make_editor(Calendar *c)
705 {
706         int             cnt = 0;
707         Arg             args[15];
708         Editor          *e = (Editor *)c->editor;
709         Props_pu        *p = (Props_pu *)c->properties_pu;
710         XmString        xmstr;
711         Dimension       label_height;
712         XtTranslations  new_translations;
713         XFontSetExtents listfontextents;
714         static char     translations[] = "\
715                 ~c ~s ~m ~a <Btn1Down>:\
716                  dtcm-process-press(ListBeginSelect,TranslationDragStart)\n\
717                 c ~s ~m ~a <Btn1Down>:\
718                  dtcm-process-press(ListBeginToggle,TranslationDragStart)";
719         static char     btn2_translations[] = "\
720                 ~c ~s ~m ~a <Btn2Down>:\
721                  dtcm-process-press(ListBeginSelect,TranslationDragStart)\n\
722                 c ~s ~m ~a <Btn2Down>:\
723                  dtcm-process-press(ListBeginToggle,TranslationDragStart)\n\
724                 <Btn2Motion>:ListButtonMotion()\n\
725                 ~c ~s ~m ~a <Btn2Up>:ListEndSelect()\n\
726                 c ~s ~m ~a <Btn2Up>:ListEndToggle()";
727         Boolean         btn1_transfer; 
728
729         new_translations = XtParseTranslationTable(translations);
730                          
731         e->cal = c;
732
733         /*
734         **  Dialog shell and the base form
735         */
736         e->frame = XtVaCreatePopupShell("frame",
737                 xmDialogShellWidgetClass, e->cal->frame,
738                 XmNdeleteResponse,      XmDO_NOTHING,
739                 XmNallowShellResize,    True,
740                 NULL);
741         set_editor_title(e, c->view->current_calendar);
742         setup_quit_handler(e->frame, e_quit_handler, (caddr_t)e);
743
744         e->base_form_mgr = XtVaCreateWidget("base_form_mgr",
745                 xmFormWidgetClass,      e->frame,
746                 XmNautoUnmanage,        False,
747                 XmNfractionBase,        8,
748                 NULL);
749
750         /*
751         **  Build the stuff in the upper portion of the form - the dssw widget,
752         **  the scrolling appointment list, the expand/contract button, and the
753         **  first separator.
754         */
755         xmstr = XmStringCreateLocalized(
756                                 catgets(c->DT_catd, 1, 628, "Time  What"));
757         e->list_label = XtVaCreateWidget("label",
758                 xmLabelGadgetClass,     e->base_form_mgr,
759                 XmNlabelString,         xmstr,
760                 XmNtopAttachment,       XmATTACH_FORM,
761                 XmNtopOffset,           5,
762                 NULL);
763         XmStringFree(xmstr);
764
765         XtVaGetValues(e->list_label, XmNheight, &label_height, NULL);
766
767         e->message_text = XtVaCreateWidget("message",
768                 xmLabelGadgetClass,     e->base_form_mgr,
769                 XmNalignment,           XmALIGNMENT_BEGINNING,
770                 XmNbottomAttachment,    XmATTACH_FORM,
771                 XmNbottomOffset,        2,
772                 XmNleftAttachment,      XmATTACH_FORM,
773                 XmNleftOffset,          2,
774                 XmNrightAttachment,     XmATTACH_FORM,
775                 XmNrightOffset,         2,
776                 NULL);
777
778         /*
779         **  Create insert, delete, change, and clear buttons
780         */
781         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 342, "Insert"));
782         e->insert_button = XtVaCreateWidget("Insert",
783                 xmPushButtonWidgetClass, e->base_form_mgr,
784                 XmNlabelString,         xmstr,
785                 XmNbottomAttachment,    XmATTACH_WIDGET,
786                 XmNbottomWidget,        e->message_text,
787                 XmNleftAttachment,      XmATTACH_POSITION,
788                 XmNleftPosition,        1,
789                 XmNrightAttachment,     XmATTACH_POSITION,
790                 XmNrightPosition,       2,
791                 NULL);
792         XtAddCallback(e->insert_button, XmNactivateCallback, e_insert_proc, e);
793         XmStringFree(xmstr);
794
795         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 343, "Change"));
796         e->change_button = XtVaCreateWidget("Change",
797                 xmPushButtonWidgetClass, e->base_form_mgr,
798                 XmNlabelString,         xmstr,
799                 XmNbottomAttachment,    XmATTACH_WIDGET,
800                 XmNbottomWidget,        e->message_text,
801                 XmNleftAttachment,      XmATTACH_POSITION,
802                 XmNleftPosition,        2,
803                 XmNrightAttachment,     XmATTACH_POSITION,
804                 XmNrightPosition,       3,
805                 XmNsensitive,           False,
806                 NULL);
807         XtAddCallback(e->change_button, XmNactivateCallback, e_change_proc, e);
808         XmStringFree(xmstr);
809  
810         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 419, "Delete"));
811         e->delete_button = XtVaCreateWidget("Delete",
812                 xmPushButtonWidgetClass, e->base_form_mgr,
813                 XmNlabelString,         xmstr,
814                 XmNbottomAttachment,    XmATTACH_WIDGET,
815                 XmNbottomWidget,        e->message_text,
816                 XmNleftAttachment,      XmATTACH_POSITION,
817                 XmNleftPosition,        3,
818                 XmNrightAttachment,     XmATTACH_POSITION,
819                 XmNrightPosition,       4,
820                 XmNsensitive,           False,
821                 NULL);
822         XtAddCallback(e->delete_button, XmNactivateCallback, e_delete_proc, e);
823         XmStringFree(xmstr);
824
825         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 803, "Clear"));
826         e->clear_button = XtVaCreateWidget("Clear",
827                 xmPushButtonWidgetClass, e->base_form_mgr,
828                 XmNlabelString,         xmstr,
829                 XmNbottomAttachment,    XmATTACH_WIDGET,
830                 XmNbottomWidget,        e->message_text,
831                 XmNleftAttachment,      XmATTACH_POSITION,
832                 XmNleftPosition,        4,
833                 XmNrightAttachment,     XmATTACH_POSITION,
834                 XmNrightPosition,       5,
835                 NULL);
836         XtAddCallback(e->clear_button, XmNactivateCallback, e_clear_proc, e);
837         XmStringFree(xmstr);
838
839         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 923, "Cancel"));
840         e->close_button = XtVaCreateWidget("Cancel",
841                 xmPushButtonWidgetClass, e->base_form_mgr,
842                 XmNlabelString,         xmstr,
843                 XmNbottomAttachment,    XmATTACH_WIDGET,
844                 XmNbottomWidget,        e->message_text,
845                 XmNleftAttachment,      XmATTACH_POSITION,
846                 XmNleftPosition,        5,
847                 XmNrightAttachment,     XmATTACH_POSITION,
848                 XmNrightPosition,       6,
849                 NULL);
850         XtAddCallback(e->close_button, XmNactivateCallback, e_close_proc, e);
851         XmStringFree(xmstr);
852
853         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
854         e->help_button = XtVaCreateWidget("Help",
855                 xmPushButtonWidgetClass, e->base_form_mgr,
856                 XmNlabelString,         xmstr,
857                 XmNbottomAttachment,    XmATTACH_WIDGET,
858                 XmNbottomWidget,        e->message_text,
859                 XmNleftAttachment,      XmATTACH_POSITION,
860                 XmNleftPosition,        6,
861                 XmNrightAttachment,     XmATTACH_POSITION,
862                 XmNrightPosition,       7,
863                 NULL);
864         XmStringFree(xmstr);
865
866         e->separator2 = XtVaCreateWidget("separator2",
867                 xmSeparatorGadgetClass, e->base_form_mgr,
868                 XmNbottomAttachment,    XmATTACH_WIDGET,
869                 XmNbottomWidget,        e->insert_button,
870                 XmNbottomOffset,        5,
871                 XmNleftAttachment,      XmATTACH_FORM,
872                 XmNleftOffset,          5,
873                 XmNrightAttachment,     XmATTACH_FORM,
874                 XmNrightOffset,         5,
875                 NULL);
876
877         e->separator1 = XtVaCreateWidget("separator1",
878                 xmSeparatorGadgetClass, e->base_form_mgr,
879                 XmNleftAttachment,      XmATTACH_FORM,
880                 XmNleftOffset,          5,
881                 XmNrightAttachment,     XmATTACH_FORM,
882                 XmNrightOffset,         5,
883                 XmNbottomAttachment,    XmATTACH_WIDGET,
884                 XmNbottomWidget,        e->separator2,
885                 NULL);
886
887         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 626, "More"));
888         e->expand_ui_button = XtVaCreateWidget("expand_ui_button",
889                 xmPushButtonWidgetClass, e->base_form_mgr,
890                 XmNlabelString,         xmstr,
891                 XmNbottomAttachment,    XmATTACH_WIDGET,
892                 XmNbottomWidget,        e->separator1,
893                 XmNbottomOffset,        3,
894                 XmNleftAttachment,      XmATTACH_FORM,
895                 XmNleftOffset,          5,
896                 XmNnavigationType,      XmTAB_GROUP,
897                 NULL);
898         XtAddCallback(e->expand_ui_button, XmNactivateCallback,
899                 e_expand_ui_proc, e);
900         XmStringFree(xmstr);
901
902         e->dsswFlags = 0;
903         build_dssw(&e->dssw, c, e->base_form_mgr, True, True);
904         XtVaSetValues(e->dssw.dssw_form_mgr,
905                 XmNtopAttachment,       XmATTACH_FORM,
906                 XmNtopOffset,           label_height + 5,
907                 XmNbottomAttachment,    XmATTACH_WIDGET,
908                 XmNbottomWidget,        e->expand_ui_button,
909                 XmNbottomOffset,        3,
910                 XmNleftAttachment,      XmATTACH_FORM,
911                 XmNleftOffset,          5,
912                 NULL);
913
914         XtAddCallback(e->dssw.start_text, XmNvalueChangedCallback,
915                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
916         XtAddCallback(e->dssw.start_am, XmNvalueChangedCallback,
917                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
918         XtAddCallback(e->dssw.start_pm, XmNvalueChangedCallback,
919                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
920         XtAddCallback(e->dssw.stop_text, XmNvalueChangedCallback,
921                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
922         XtAddCallback(e->dssw.stop_am, XmNvalueChangedCallback,
923                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
924         XtAddCallback(e->dssw.stop_pm, XmNvalueChangedCallback,
925                       clear_flag_on_modify, (XtPointer)&e->dsswFlags);
926
927         /*
928          * Add a drag source icon inside the dssw, lower right
929          */
930         xmstr = XmStringCreateLocalized(
931                                 catgets(c->DT_catd, 1, 627, "Drag Appt"));
932         e->drag_source = XtVaCreateWidget("drag_source",
933                 dtIconGadgetClass,      e->dssw.dssw_form_mgr,
934                 XmNpixmapPosition,      XmPIXMAP_TOP,
935                 XmNstringPosition,      XmSTRING_BOTTOM,
936                 XmNalignment,           XmALIGNMENT_CENTER,
937                 XmNstring,              xmstr,
938                 XmNbottomAttachment,    XmATTACH_FORM,
939                 XmNrightAttachment,     XmATTACH_FORM,
940                 XmNtraversalOn,         False,
941                 XmNbehavior,            XmICON_DRAG,
942                 NULL);
943         XmStringFree(xmstr);
944
945         XtAddEventHandler(XtParent(e->drag_source), Button1MotionMask, False,
946                 (XtEventHandler)FormApptDragMotionHandler, (XtPointer) c);
947
948         XtVaGetValues((Widget)XmGetXmDisplay(XtDisplay(c->frame)), 
949                 "enableBtn1Transfer",   &btn1_transfer, 
950                 NULL); 
951
952         /* btn1_transfer is a tri-state variable - see 1195846 */
953         if ((Boolean)btn1_transfer != True) {
954                 XtAddEventHandler(XtParent(e->drag_source), 
955                                 Button2MotionMask, False, 
956                                 (XtEventHandler)FormApptDragMotionHandler, 
957                                 (XtPointer) c);
958         }
959
960         if (p->drag_icon_xbm)
961                 XtVaSetValues(e->drag_source, 
962                                 XmNpixmap, p->drag_icon_xbm, 
963                                 NULL);
964
965         XtVaSetValues(e->dssw.what_scrollwindow, 
966                 XmNrightAttachment,     XmATTACH_WIDGET,
967                 XmNrightWidget,         e->drag_source, 
968                 NULL);
969
970         ManageChildren(e->dssw.dssw_form_mgr);
971
972         CalFontExtents(c->fonts->labelfont, &listfontextents);
973
974         cnt = 0;
975         XtSetArg(args[cnt], XmNlistSizePolicy, XmCONSTANT);             ++cnt;
976         XtSetArg(args[cnt], XmNwidth, 15 * 
977                 listfontextents.max_logical_extent.width);              ++cnt;
978         XtSetArg(args[cnt], XmNscrollBarDisplayPolicy, XmSTATIC);       ++cnt;
979         XtSetArg(args[cnt], XmNdoubleClickInterval, 5);                 ++cnt;
980         e->appt_list = XmCreateScrolledList(e->base_form_mgr, "appt_list",
981                                             args, cnt);
982         e->appt_list_sw = XtParent(e->appt_list);
983
984         XtOverrideTranslations(e->appt_list, new_translations);
985
986         /* Make btn 2 do dnd of appts */
987         /* btn1_transfer is a tri-state variable - see 1195846 */
988         if ((Boolean)btn1_transfer != True) {
989                 new_translations = XtParseTranslationTable(btn2_translations);
990                 XtOverrideTranslations(e->appt_list, new_translations);
991         }
992
993         XtVaSetValues(e->appt_list_sw,
994                 XmNtopAttachment,       XmATTACH_FORM,
995                 XmNtopOffset,           label_height + 11,
996                 XmNleftAttachment,      XmATTACH_WIDGET,
997                 XmNleftWidget,          e->dssw.dssw_form_mgr,
998                 XmNleftOffset,          10,
999                 XmNrightAttachment,     XmATTACH_FORM,
1000                 XmNrightOffset,         5,
1001                 XmNbottomAttachment,    XmATTACH_WIDGET,
1002                 XmNbottomWidget,        e->expand_ui_button,
1003                 XmNbottomOffset,        3,
1004                 NULL);
1005
1006         XtManageChild(e->appt_list);
1007         XtAddCallback(e->appt_list,
1008                 XmNbrowseSelectionCallback, e_list_select_proc, e); 
1009
1010         XtVaSetValues(e->list_label,
1011                 XmNleftAttachment,      XmATTACH_OPPOSITE_WIDGET,
1012                 XmNleftWidget,          e->appt_list_sw,
1013                 NULL);
1014
1015         XtAddCallback(e->help_button, XmNactivateCallback,
1016                 (XtCallbackProc)help_cb, APPT_EDITOR_HELP_BUTTON);
1017         XtAddCallback(e->base_form_mgr, XmNhelpCallback,
1018                 (XtCallbackProc)help_cb, (XtPointer) APPT_EDITOR_HELP_BUTTON);
1019
1020         XtVaSetValues(e->base_form_mgr, 
1021                 XmNdefaultButton,       e->insert_button, 
1022                 NULL);
1023
1024         XtVaSetValues(e->base_form_mgr, 
1025                 XmNcancelButton,        e->close_button, 
1026                 NULL);
1027
1028         XmProcessTraversal(e->dssw.what_text, XmTRAVERSE_CURRENT);
1029         XtVaSetValues(e->base_form_mgr, 
1030                 XmNinitialFocus,        e->dssw.what_text, 
1031                 NULL);
1032
1033         ManageChildren(e->base_form_mgr);
1034         XtManageChild(e->base_form_mgr);
1035
1036         /*
1037         **  Set up editor variables.  The drag threshold variables are set to
1038         **  -1, so we are ready for first dnd operation.
1039         */
1040         rfp_init(&e->rfp, c, e->base_form_mgr);
1041         reminders_init(&e->reminders, c, e->base_form_mgr);
1042         e->appt_count = 0;
1043         e->appt_head = NULL;
1044         e->initialX = -1;
1045         e->initialY = -1;
1046         e->doing_drag = False;
1047 }
1048
1049 /*******************************************************************************
1050 **
1051 **  External functions
1052 **
1053 *******************************************************************************/
1054 extern void
1055 add_to_appt_list(CSA_entry_handle entry, Editor *e) {
1056         char                    buf[DEFAULT_APPT_LEN];
1057         Props                   *p = (Props *)e->cal->properties;
1058         XmString                str;
1059         CSA_return_code         status;
1060         DisplayType             dt = get_int_prop(p, CP_DEFAULTDISP);
1061         Dtcm_appointment        *appt;
1062
1063         appt = allocate_appt_struct(appt_read,
1064                                     e->cal->general->version,
1065                                     CSA_ENTRY_ATTR_START_DATE_I,
1066                                     CSA_ENTRY_ATTR_SUMMARY_I,
1067                                     CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
1068                                     NULL);
1069         status = query_appt_struct(e->cal->cal_handle, entry, appt);
1070         backend_err_msg(e->frame, e->cal->view->current_calendar, status,
1071                         ((Props_pu *)e->cal->properties_pu)->xm_error_pixmap);
1072         if (status != CSA_SUCCESS) {
1073                 free_appt_struct(&appt);
1074                 return;
1075         }
1076
1077         format_appt(appt, buf, dt, DEFAULT_APPT_LEN);
1078         str = XmStringCreateLocalized(buf);
1079         XmListAddItem(e->appt_list, str, 0);
1080         XmStringFree(str);
1081         free_appt_struct(&appt);
1082 }
1083
1084 extern void
1085 add_all_appt(Editor *e) {
1086         int             i;
1087         CSA_uint32      j;
1088         char            *date;
1089         Tick            tick;
1090         Props           *p;
1091         Calendar        *c = e->cal;
1092         CSA_entry_handle        *entry_list;
1093         OrderingType    o;
1094         SeparatorType   s;
1095
1096         if (!editor_showing(e))
1097                 return;
1098
1099         p = (Props *)e->cal->properties;
1100         o = get_int_prop(p, CP_DATEORDERING);
1101         s = get_int_prop(p, CP_DATESEPARATOR);
1102
1103         date = get_date_from_widget(e->cal->view->date, e->dssw.date_text, o, s);
1104         if (!date || (tick = cm_getdate(date, NULL)) <= 0)
1105                 return;
1106         build_editor_list(e, tick, dayGlance, &entry_list, &j);
1107
1108         XmListDeleteAllItems(e->appt_list);
1109         XtSetSensitive(e->delete_button, False);
1110         XtSetSensitive(e->change_button, False);
1111         if (e->appt_head && e->appt_count >= 0)
1112                 csa_free(e->appt_head); 
1113         e->appt_head = entry_list;
1114         e->appt_count = j;
1115         for (i = 0; i < j; i++)
1116                 add_to_appt_list(entry_list[i], e);
1117         if (j <= 0)
1118                 XtSetSensitive(e->appt_list, False);
1119         else
1120                 XtSetSensitive(e->appt_list, True);
1121 }
1122
1123
1124 static void
1125 set_list_title(Editor *e) {
1126         Calendar        *c = e->cal;
1127         Props           *p = (Props *)c->properties;
1128         char            *header;
1129         char            buffer[BUFSIZ];
1130         char            buffer2[BUFSIZ];
1131         XmString        xmstr;
1132
1133         switch (e->view_list_glance) {
1134                 case yearGlance:
1135                                 header = catgets(c->DT_catd, 1, 704, "Year of %d");
1136                                 sprintf(buffer, header, year(e->view_list_date));
1137                                 break;
1138                 case monthGlance:
1139                                 header = catgets(c->DT_catd, 1, 705, "%s");
1140                                 format_date(e->view_list_date+1, get_int_prop(p, CP_DATEORDERING), buffer2, 0, 0, 0);
1141                                 sprintf(buffer, header, buffer2);
1142                                 break;
1143                 case weekGlance:
1144                                 header = catgets(c->DT_catd, 1, 706, "Week of %s");
1145                                 format_date(e->view_list_date+1, get_int_prop(p, CP_DATEORDERING), buffer2, 1, 0, 0);
1146                                 sprintf(buffer, header, buffer2);
1147                                 break;
1148                 case dayGlance:
1149                                 header = catgets(c->DT_catd, 1, 707, "%s");
1150                                 format_date(e->view_list_date+1, get_int_prop(p, CP_DATEORDERING), buffer2, 1, 0, 0);
1151                                 sprintf(buffer, header, buffer2);
1152                                 break;
1153         }
1154         if (e->view_frame) {
1155                 xmstr = XmStringCreateLocalized(buffer);
1156                 XtVaSetValues(e->view_list_label, XmNlabelString, xmstr,
1157                         NULL);
1158                 XmStringFree(xmstr);
1159         }
1160 }
1161 extern void
1162 build_editor_list(Editor *e, Tick date, Glance glance,
1163                   CSA_entry_handle **entry_list, CSA_uint32 *count) {
1164         int                     range_count;
1165         time_t                  start, stop;
1166         CSA_return_code         status;
1167         CSA_enum                *ops;
1168         CSA_attribute           *range_attr;
1169
1170         switch(glance) {
1171         case yearGlance:
1172                 start = lowerbound(jan1(date));
1173                 stop = nextyear(start) - 1;
1174                 break;
1175         case monthGlance:
1176                 start = first_dom(date);
1177                 stop = nextmonth(start) - 1;
1178                 break;
1179         case weekGlance:
1180                 start = first_dow(date);
1181                 stop = nextweek(start) - 1;
1182                 break;
1183         case dayGlance:
1184         default:
1185                 start = lowerbound(date);
1186                 stop = nextday(start) - 1;
1187                 break;
1188         }
1189
1190         setup_range(&range_attr, &ops, &range_count, start, stop,
1191                     CSA_TYPE_EVENT, NULL, B_FALSE, e->cal->general->version);
1192
1193         status = csa_list_entries(e->cal->cal_handle, range_count, range_attr, ops, count, entry_list, NULL);
1194         backend_err_msg(e->frame, e->cal->view->current_calendar, status,
1195                         ((Props_pu *)e->cal->properties_pu)->xm_error_pixmap);
1196         if (status != CSA_SUCCESS) {
1197                 *entry_list = NULL;
1198                 *count = 0;
1199         }
1200         free_range(&range_attr, &ops, range_count);
1201 }
1202
1203 extern int
1204 build_editor_view(Editor *e, Glance glance, Boolean redisplay) {
1205         int                     cnt;
1206         CSA_uint32              entry_count;
1207         char                    *buf, *what_str, str1[MAXNAMELEN],
1208                                 str2[MAXNAMELEN];
1209         CSA_entry_handle        *entry_list;
1210         Lines                   *lines;
1211         Props                   *p = (Props *)e->cal->properties;
1212         XmString                str;
1213         CSA_return_code         status;
1214         OrderingType            o = get_int_prop(p, CP_DATEORDERING);
1215         SeparatorType           s = get_int_prop(p, CP_DATESEPARATOR);
1216         DisplayType             dt = get_int_prop(p, CP_DEFAULTDISP);
1217         Dtcm_appointment        *appt;
1218         Tick                    start_time;
1219
1220         /*
1221         **  First, get the list of appointments and delete all items from the
1222         **  list
1223         */
1224
1225         if (redisplay == True) {
1226  
1227                 /* On a redisplay, rebuild the list based on the
1228                    parameters of the last query. */
1229  
1230                 build_editor_list(e, e->view_list_date, e->view_list_glance, &entry_list,
1231                                 &entry_count);
1232         }
1233         else {
1234                 /* If this is a clean display of the appointment list,
1235                    save the context so that a redisplay can be done if
1236                    something changes, like the display format or something
1237                    like that. */
1238  
1239                 build_editor_list(e, e->cal->view->date, glance, &entry_list,
1240                                 &entry_count);
1241  
1242                 e->view_list_glance = glance;
1243                 e->view_list_date = e->cal->view->date;
1244         }
1245
1246         set_list_title(e);
1247
1248         XmListDeleteAllItems(e->view_list);
1249
1250         /*
1251         **  Now loop through and add each appt to the list
1252         */
1253         appt = allocate_appt_struct(appt_read,
1254                                     e->cal->general->version,
1255                                     CSA_ENTRY_ATTR_START_DATE_I,
1256                                     CSA_ENTRY_ATTR_SUMMARY_I,
1257                                     NULL);
1258         for (cnt = 0; cnt < entry_count; cnt++) {
1259                 /*
1260                 **  Create the text string describing the editor and set that
1261                 **  value in the scrolling list
1262                 */
1263                 status = query_appt_struct(e->cal->cal_handle, entry_list[cnt], appt);
1264                 backend_err_msg(e->frame, e->cal->view->current_calendar, status,
1265                         ((Props_pu *)e->cal->properties_pu)->xm_error_pixmap);
1266                 if (status != CSA_SUCCESS) {
1267                         csa_free(entry_list);
1268                         free_appt_struct(&appt);
1269                         entry_count = cnt = 0;
1270                         continue;
1271                 }
1272
1273                 _csa_iso8601_to_tick(appt->time->value->item.date_time_value, &start_time);
1274                 format_tick(start_time, o, s, str1);
1275                 format_time(start_time, dt, str2);
1276                 lines = text_to_lines(appt->what->value->item.string_value, 1);
1277                 if (lines && lines->s) {
1278                         buf = (char *)ckalloc(cm_strlen(str1) + cm_strlen(str2)
1279                                               + cm_strlen(lines->s) + 5);
1280                         what_str = lines->s;
1281                 } else {
1282                         buf = (char *)ckalloc(cm_strlen(str1)
1283                                               + cm_strlen(str2) + 6);
1284                         what_str = "\0";
1285                 }
1286
1287                 sprintf(buf, "%s  %s  %s", str1, str2, what_str);
1288                 str = XmStringCreateLocalized(buf);
1289                 XmListAddItem(e->view_list, str, 0);
1290
1291                 XmStringFree(str);
1292                 free(buf);
1293                 destroy_lines(lines);
1294         }
1295         if (entry_list && entry_count > 0)
1296                 csa_free(entry_list);
1297         free_appt_struct(&appt);
1298
1299         if (entry_count <= 0)
1300                 XtSetSensitive(e->view_list, False);
1301         else
1302                 XtSetSensitive(e->view_list, True);
1303
1304         return (cnt);
1305 }
1306
1307 boolean_t
1308 compare_repeat_info(
1309         Dtcm_appointment        *old_a,
1310         RFP                     *rfp,
1311         CSA_session_handle      cal_handle,
1312         int                     cal_version)
1313 {
1314         Dtcm_appointment        *appt;
1315         CSA_return_code          status;
1316         CSA_enum                 ops[1];
1317         CSA_entry_handle        *entries;
1318         CSA_uint32               num_entries;
1319
1320         /* Find the start date of the appointment.  If it matches the
1321          * current appt then we don't care if the rules match because we
1322          * allow changes to the rules when you start from the first
1323          * appt.
1324          */
1325         ops[0] = CSA_MATCH_EQUAL_TO;
1326
1327         status = csa_list_entries(cal_handle, 1, old_a->identifier, ops,
1328                         &num_entries, &entries, NULL);
1329
1330         if (status != CSA_SUCCESS || num_entries == 0) {
1331                 return FALSE;
1332         }
1333
1334         appt = allocate_appt_struct(appt_read,
1335                                     cal_version,
1336                                     CSA_ENTRY_ATTR_START_DATE_I,
1337                                     NULL);
1338         status = query_appt_struct(cal_handle, entries[0], appt);
1339         if (status != CSA_SUCCESS) {
1340                 free_appt_struct(&appt);
1341                 return FALSE;
1342         }
1343
1344         csa_free(entries);
1345
1346         if (!strcmp(old_a->time->value->item.date_time_value,
1347                     appt->time->value->item.date_time_value)) {
1348                 free_appt_struct(&appt);
1349                 return TRUE;
1350         }
1351  
1352         free_appt_struct(&appt);
1353  
1354         /* We're not at the first event so we check to see if the rule
1355          * has changed.
1356          */
1357         if (!old_a->repeat_type->value)
1358                 return FALSE;
1359  
1360         if (old_a->repeat_type->value->item.sint32_value !=
1361             rfp->repeat_type)
1362                 return FALSE;
1363
1364         if (!old_a->repeat_interval || !old_a->repeat_interval->value)
1365                 return TRUE;
1366
1367         if (rfp->repeat_type == CSA_X_DT_REPEAT_EVERY_NDAY ||
1368             rfp->repeat_type == CSA_X_DT_REPEAT_EVERY_NWEEK ||
1369             rfp->repeat_type == CSA_X_DT_REPEAT_EVERY_NMONTH)
1370                 if (old_a->repeat_interval->value->item.sint32_value !=
1371                     rfp->repeat_nth)
1372                         return FALSE;
1373
1374         return TRUE;                  
1375 }
1376
1377 void
1378 trim_end_date_from_rule(char *rule, char *newrule)
1379 {
1380         char    *ptr;
1381
1382         /* this is done with the assumption that 'Z' only appears
1383          * in the end date of the rule and that there is at most
1384          * one end date in the rule and that the end date is
1385          * is always at the end of the rule
1386          */
1387         if (ptr = strchr(rule, 'Z')) {
1388                 while (*ptr != ' ')
1389                         ptr--;
1390                 *ptr = NULL;
1391         }
1392         strcpy(newrule, rule);
1393
1394         if (ptr)
1395                 *ptr = ' ';
1396 }
1397
1398 /*
1399  * A single event in a repeating appt is beinging changed.  If the rule is
1400  * not being changed then we need to change it to D1 #1 since the change
1401  * is suppose to effect this appt only.
1402  */
1403 void
1404 change_rule_for_this_one_only(
1405         Calendar         *c,
1406         Dtcm_appointment *new, 
1407         Dtcm_appointment *old)
1408 {
1409         char    buf[BUFSIZ];
1410
1411         if (c->general->version < DATAVER4) {
1412                 if ((new->repeat_type->value->item.sint32_value ==
1413                      old->repeat_type->value->item.sint32_value) &&
1414                     (new->repeat_times->value->item.uint32_value ==
1415                      old->repeat_times->value->item.uint32_value)) {
1416                         new->repeat_type->value->item.sint32_value =
1417                                                 CSA_X_DT_REPEAT_ONETIME;
1418                         new->repeat_times->value->item.uint32_value = 0;
1419                 }
1420         } else {
1421                 /* an end date might be added to the rule if the user
1422                  * has done a delete/change forward operation on this
1423                  * appointment before.  We need to get rid of the
1424                  * end date from the rule otherwise the 2 rules
1425                  * won't match
1426                  */
1427                 trim_end_date_from_rule(old->recurrence_rule->value->\
1428                         item.string_value, buf); 
1429                 if (!strcmp(new->recurrence_rule->value->item.string_value,
1430                             buf)) {
1431                         free (new->recurrence_rule->value->item.string_value);
1432                         new->recurrence_rule->value->item.string_value =
1433                                                 cm_strdup("D1 #1");
1434                 }
1435         }
1436 }
1437
1438 extern Boolean
1439 editor_change(Dtcm_appointment *new_a, CSA_entry_handle old_a, CSA_entry_handle *updated_a,
1440               Calendar *c) {
1441         Editor                  *e = (Editor *)c->editor;
1442         Props_pu                *p = (Props_pu *)c->properties_pu;
1443         CSA_return_code         stat;
1444         CSA_enum                scope;
1445         Dtcm_appointment        *appt;
1446         static int              answer;
1447
1448         answer = 0;
1449         appt = allocate_appt_struct(appt_read,
1450                                     c->general->version,
1451                                     CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
1452                                     CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
1453                                     CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
1454                                     CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
1455                                     CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I,
1456                                     CSA_ENTRY_ATTR_START_DATE_I,
1457                                     CSA_ENTRY_ATTR_RECURRENCE_RULE_I,
1458                                     NULL);
1459         stat = query_appt_struct(c->cal_handle, old_a, appt);
1460         backend_err_msg(e->frame, c->view->current_calendar, stat,
1461                         p->xm_error_pixmap);
1462         if (stat != CSA_SUCCESS) {
1463                 free_appt_struct(&appt);
1464                 return FALSE;
1465         }
1466
1467         if ((appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER) ||
1468             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_WEEKLY) ||
1469             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_MONTHLY) ||
1470             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_YEARLY)) {
1471                 char *title = XtNewString(catgets(c->DT_catd, 1, 258,
1472                                       "Calendar : Appointment Editor - Change"));
1473                 char *text = XtNewString(catgets(c->DT_catd, 1, 708,
1474                                         "This appointment repeats in an unknown fashion.  All occurrences will be changed\nDo you still wish to change it?"));
1475                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1476                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1477                 answer = dialog_popup(e->frame,
1478                                 DIALOG_TITLE, title,
1479                                 DIALOG_TEXT, text,
1480                                 BUTTON_IDENT, 1, ident1,
1481                                 BUTTON_IDENT, 4, ident4,
1482                                 DIALOG_IMAGE, p->xm_question_pixmap,
1483                                 NULL);
1484                 XtFree(ident4);
1485                 XtFree(ident1);
1486                 XtFree(text);
1487                 XtFree(title);
1488         }
1489         else if (appt->repeat_type->value->item.sint32_value != 
1490                 CSA_X_DT_REPEAT_ONETIME) {
1491                 char *title = XtNewString(catgets(c->DT_catd, 1, 258,
1492                                 "Calendar : Appointment Editor - Change"));
1493                 char *text = XtNewString(catgets(c->DT_catd, 1, 268,
1494                                 "This appointment is part of a repeating series.\nDo you want to change ...?"));
1495                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1496                 char *ident2 = XtNewString(catgets(c->DT_catd, 1, 270,
1497                                 "This One Only"));
1498                 char *ident3 = XtNewString(catgets(c->DT_catd, 1, 271, "Forward"));
1499                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 272, "All"));
1500                 answer = dialog_popup(e->frame,
1501                         DIALOG_TITLE, title,
1502                         DIALOG_TEXT, text,
1503                         BUTTON_IDENT, 1, ident1,
1504                         BUTTON_IDENT, 2, ident2,
1505                         BUTTON_IDENT, 3, ident3,
1506                         (compare_repeat_info(appt, &(e->rfp), c->cal_handle, c->general->version) ?
1507                                 BUTTON_IDENT : BUTTON_INSENSITIVE), 
1508                                         4, ident4,
1509                         DIALOG_IMAGE, p->xm_question_pixmap,
1510                         NULL);
1511                 XtFree(ident4);
1512                 XtFree(ident3);
1513                 XtFree(ident2);
1514                 XtFree(ident1);
1515                 XtFree(text);
1516                 XtFree(title);
1517                 if (answer == 2)
1518                         change_rule_for_this_one_only(c, new_a, appt);
1519         }
1520
1521         switch(answer) {
1522         case 1:
1523                 free_appt_struct(&appt);
1524                 return False;
1525         case 2:
1526                 scope = CSA_SCOPE_ONE;
1527                 break;
1528         case 3:
1529                 scope = CSA_SCOPE_FORWARD;
1530                 break;
1531         case 4:
1532         default:
1533                 scope = CSA_SCOPE_ALL;
1534                 break;
1535         }
1536
1537         /* We are not allowed to change the type of the entry, so we will 
1538            remove that particular entry from the list for writing. */
1539
1540         if (new_a->type) {
1541                 if (new_a->type->name){
1542                         free(new_a->type->name);
1543                         new_a->type->name = NULL;
1544                 }
1545         }
1546
1547         /* if the repeat type/times is changed, reset the sequence end date */
1548         if (c->general->version == DATAVER3 &&
1549             appt->repeat_type->value->item.sint32_value !=
1550             CSA_X_DT_REPEAT_ONETIME &&
1551             (appt->repeat_type->value->item.sint32_value !=
1552              new_a->repeat_type->value->item.sint32_value ||
1553              appt->repeat_times->value->item.uint32_value !=
1554              new_a->repeat_times->value->item.uint32_value))
1555         {
1556                 if (new_a->sequence_end_date && new_a->sequence_end_date->value)
1557                 {
1558                         if (new_a->sequence_end_date->value->item.date_time_value)
1559                                 free(new_a->sequence_end_date->value->\
1560                                         item.date_time_value);
1561                         free(new_a->sequence_end_date->value);
1562                         new_a->sequence_end_date->value = NULL;
1563                 }
1564         } else {
1565                 if (new_a->sequence_end_date && new_a->sequence_end_date->name)
1566                 {
1567                         free (new_a->sequence_end_date->name);
1568                         new_a->sequence_end_date->name = NULL;
1569                 }
1570         }
1571
1572         free_appt_struct(&appt);
1573
1574         stat = csa_update_entry_attributes(c->cal_handle, old_a, scope, CSA_FALSE, new_a->count, new_a->attrs, updated_a, NULL);
1575         backend_err_msg(e->frame, c->view->current_calendar, stat,
1576                         p->xm_error_pixmap);
1577         if (stat != CSA_SUCCESS)
1578                 return FALSE;
1579
1580         set_editor_msg_defaults(e);
1581         add_all_appt(e);
1582         if (editor_view_showing(e))
1583                 build_editor_view(e, dayGlance, False);
1584
1585         if (geditor_showing((GEditor *)calendar->geditor))
1586                 add_all_gappt((GEditor *)calendar->geditor);
1587
1588         reset_alarm(c);
1589         invalidate_cache(c);
1590         paint_canvas(c, NULL, RENDER_CLEAR_FIRST);
1591
1592         if (c->browser)
1593                 br_display(c);
1594
1595         if (geditor_showing((GEditor *)c->geditor))
1596                 add_all_gappt((GEditor *)c->geditor);
1597
1598         return True;
1599 }
1600
1601 extern void
1602 editor_clean_up(Editor *e) {
1603         if (e->appt_head && e->appt_count >= 0)
1604                 csa_free(e->appt_head); 
1605         e->appt_head = NULL;
1606         e->appt_count = 0;
1607 }
1608
1609 extern Boolean
1610 editor_delete(CSA_entry_handle entry, Calendar *c) {
1611         Editor                  *e = (Editor *)c->editor;
1612         Props_pu                *p = (Props_pu *)c->properties_pu;
1613         CSA_return_code         stat;
1614         CSA_enum                scope;
1615         Dtcm_appointment        *appt;
1616         static int      answer;
1617
1618         answer = 0;
1619         appt = allocate_appt_struct(appt_read, 
1620                                 c->general->version,
1621                                 CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I, 
1622                                 NULL);
1623         stat = query_appt_struct(c->cal_handle, entry, appt);
1624         backend_err_msg(e->frame, c->view->current_calendar, stat,
1625                         p->xm_error_pixmap);
1626         if (stat != CSA_SUCCESS) {
1627                 free_appt_struct(&appt);
1628                 return False;
1629         }
1630
1631         if (appt->repeat_type->value) {
1632                 if (appt->repeat_type->value->item.sint32_value != CSA_X_DT_REPEAT_ONETIME) {
1633                         char *title = XtNewString(catgets(c->DT_catd, 1, 252,
1634                                       "Calendar : Appointment Editor - Delete"));
1635                         char *text = XtNewString(catgets(c->DT_catd, 1, 274,
1636                                         "This appointment is part of a repeating series.\nDo you want to delete ...?"));
1637                         char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1638                         char *ident2 = XtNewString(catgets(c->DT_catd, 1, 270,
1639                                         "This One Only"));
1640                         char *ident3 = XtNewString(catgets(c->DT_catd, 1, 271, "Forward"));
1641                         char *ident4 = XtNewString(catgets(c->DT_catd, 1, 272, "All"));
1642                         answer = dialog_popup(e->frame,
1643                                 DIALOG_TITLE, title,
1644                                 DIALOG_TEXT, text,
1645                                 BUTTON_IDENT, 1, ident1,
1646                                 BUTTON_IDENT, 2, ident2,
1647                                 BUTTON_IDENT, 3, ident3,
1648                                 BUTTON_IDENT, 4, ident4,
1649                                 DIALOG_IMAGE, p->xm_question_pixmap,
1650                                 NULL);
1651                         XtFree(ident4);
1652                         XtFree(ident3);
1653                         XtFree(ident2);
1654                         XtFree(ident1);
1655                         XtFree(text);
1656                         XtFree(title);
1657                 }
1658         }
1659         else if (appt->recurrence_rule->value) {
1660                 char *title = XtNewString(catgets(c->DT_catd, 1, 252,
1661                                       "Calendar : Appointment Editor - Delete"));
1662                 char *text = XtNewString(catgets(c->DT_catd, 1, 711,
1663                                         "This appointment repeats in an unknown fashion.  All occurrences will be deleted\nDo you still wish to delete it?"));
1664                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1665                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1666                 answer = dialog_popup(e->frame,
1667                                 DIALOG_TITLE, title,
1668                                 DIALOG_TEXT, text,
1669                                 BUTTON_IDENT, 1, ident1,
1670                                 BUTTON_IDENT, 4, ident4,
1671                                 DIALOG_IMAGE, p->xm_question_pixmap,
1672                                 NULL);
1673                 XtFree(ident4);
1674                 XtFree(ident1);
1675                 XtFree(text);
1676                 XtFree(title);
1677         }
1678         free_appt_struct(&appt);
1679
1680         switch(answer) {
1681         case 1:
1682                 return False;
1683         case 2:
1684                 scope = CSA_SCOPE_ONE;
1685                 break;
1686         case 3:
1687                 scope = CSA_SCOPE_FORWARD;
1688                 break;
1689         case 4:
1690         default:
1691                 scope = CSA_SCOPE_ALL;
1692                 break;
1693         }
1694
1695         stat = csa_delete_entry(c->cal_handle, entry, scope, NULL);
1696         backend_err_msg(e->frame, c->view->current_calendar, stat,
1697                         p->xm_error_pixmap);
1698         if (stat != CSA_SUCCESS)
1699                 return FALSE;
1700
1701         set_editor_msg_defaults(e);
1702         add_all_appt(e);
1703         if (editor_view_showing(e))
1704                 build_editor_view(e, dayGlance, False);
1705         reset_alarm(c);
1706         invalidate_cache(c);
1707         paint_canvas(c, NULL, RENDER_CLEAR_FIRST);
1708
1709         if (c->browser)
1710                 br_display(c);
1711
1712         return True;
1713 }
1714
1715 extern Boolean
1716 editor_insert(Dtcm_appointment *appt, CSA_entry_handle *new_a, Calendar *c) {
1717         CSA_return_code stat;
1718         Editor          *e = (Editor *)c->editor;
1719         Props_pu        *p = (Props_pu *)c->properties_pu;
1720         CSA_enum                scope;
1721         static int              answer=0;
1722
1723         /* the gui does not support specifying the sequence end date */
1724         if (appt->sequence_end_date && appt->sequence_end_date->name) {
1725                 free(appt->sequence_end_date->name);
1726                 appt->sequence_end_date->name = NULL;
1727         }
1728
1729         if ((appt->repeat_type) && (appt->repeat_type->value) &&
1730            (appt->repeat_type->value->item.sint32_value != CSA_X_DT_REPEAT_ONETIME))
1731         {
1732                 char *title = XtNewString(catgets(c->DT_catd, 1, 1101,
1733                                         "Insert Appointment"));
1734                 char *text = XtNewString(catgets(c->DT_catd, 1, 984,
1735                                         "This appointment is part of a repeating series.\nDo you want to insert appointment ...?"));
1736                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1737                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 272, "All"));
1738                         answer = dialog_popup(e->frame,
1739                                 DIALOG_TITLE, title,
1740                                 DIALOG_TEXT, text,
1741                                 BUTTON_IDENT, 1, ident1,
1742                                 BUTTON_IDENT, 4, ident4,
1743                                 DIALOG_IMAGE, p->xm_question_pixmap,
1744                                 NULL);
1745                 XtFree(ident4);
1746                 XtFree(ident1);
1747                 XtFree(text);
1748                 XtFree(title);
1749         }
1750
1751         switch(answer) {
1752         case 1:
1753                 /*
1754                  * Free the CSA_buffer here since before, this routine
1755                  * only returned false when failure to obtain the CSA_structure
1756                  * occurred.
1757                  */
1758                 csa_free((CSA_buffer)new_a);
1759                 return 2;
1760         case 4:
1761         default:
1762                 /*
1763                  * scope is not used at this time.  However, to follow
1764                  * the change/delete style, this is here so in case
1765                  * later the same type of dialog is required.
1766                  */
1767                 scope = CSA_SCOPE_ALL;
1768                 break;
1769         }
1770
1771         stat = csa_add_entry(c->cal_handle, appt->count, appt->attrs, new_a, NULL);
1772         backend_err_msg(c->frame, c->view->current_calendar, stat,
1773                         p->xm_error_pixmap);
1774         if (stat != CSA_SUCCESS)
1775                 return FALSE;
1776
1777         set_editor_msg_defaults(e);
1778         add_all_appt(e);
1779         if (editor_view_showing(e))
1780                 build_editor_view(e, dayGlance, False);
1781
1782         if (geditor_showing((GEditor *)calendar->geditor))
1783                 add_all_gappt((GEditor *)calendar->geditor);
1784
1785         reset_alarm(c);
1786         invalidate_cache(c);
1787         paint_canvas(c, NULL, RENDER_CLEAR_FIRST);
1788
1789         if (c->browser)
1790                 br_display(c);
1791         return True;
1792 }
1793
1794 extern Boolean
1795 editor_created(Editor *e) {
1796         if (!e || !e->base_form_mgr)
1797                 return False;
1798         return True;
1799 }
1800
1801 /*
1802 **  Return the nth appointment from the array
1803 */
1804 extern CSA_entry_handle
1805 editor_nth_appt(Editor *e, int idx) {
1806         if (idx >= 0 && idx < e->appt_count)
1807                 return e->appt_head[idx];
1808         return 0;
1809 }
1810
1811 extern Boolean
1812 editor_showing(Editor *e) {
1813         if (e)
1814                 return e->editor_is_up;
1815         return False;
1816 }
1817
1818 extern Boolean
1819 editor_view_showing(Editor *e) {
1820         if (e)
1821                 return e->editor_view_is_up;
1822         return False;
1823 }
1824
1825 /*
1826 **  External function to set editor defaults
1827 */
1828 extern void
1829 set_editor_defaults(Editor *e, Tick start, Tick stop, Boolean show_notime) {
1830         if (start > 0 || stop > 0) {
1831                 load_dssw_times(&e->dssw, start, stop, show_notime);
1832                 set_dssw_defaults(&e->dssw, e->cal->view->date, False);
1833         } else
1834                 set_dssw_defaults(&e->dssw, e->cal->view->date, True);
1835         if (e->reminders.bfpm_form_mgr) {
1836                 set_rfp_defaults(&e->rfp);
1837                 set_reminders_defaults(&e->reminders);
1838         }
1839         set_message(e->message_text, " ");
1840
1841         e->dsswFlags = 0;
1842         e->rfpFlags = 0;
1843 }
1844
1845 extern void
1846 set_editor_title(Editor *e, char *name) {
1847         char            buf[MAXNAMELEN];
1848         Calendar        *c = e->cal;
1849
1850         if (e->frame) {
1851                 sprintf(buf, "%s - %s", catgets(c->DT_catd, 1, 279,
1852                         "Calendar : Appointment Editor"), name);
1853                 XtVaSetValues(e->frame, XmNtitle, buf,
1854                         NULL);
1855         }
1856 }
1857
1858 extern void
1859 set_editor_vals(Editor *e, Tick start, Tick stop) {
1860         if (start > 0 || stop > 0)
1861                 load_dssw_times(&e->dssw, start, stop, False);
1862         set_dssw_vals(&e->dssw, e->cal->view->date);
1863         set_rfp_vals(&e->rfp);
1864         set_reminders_vals(&e->reminders, True);
1865 }
1866
1867 extern void
1868 show_editor(Calendar *c, time_t start, time_t stop, Boolean show_notime) {
1869         Editor  *e = (Editor *)c->editor;
1870
1871         if (!editor_created(e))
1872                 e_make_editor(c);
1873         else if (!XtIsManaged(e->base_form_mgr))
1874                 XtManageChild(e->base_form_mgr);
1875         else
1876                 XRaiseWindow(XtDisplay(e->base_form_mgr),
1877                              XtWindow(XtParent(e->base_form_mgr)));
1878         if (!editor_showing(e)) {
1879                 ds_position_popup(c->frame, e->frame, DS_POPUP_LOR);
1880                 XmProcessTraversal(e->dssw.what_text, XmTRAVERSE_CURRENT);
1881                 XtVaSetValues(e->base_form_mgr, 
1882                                 XmNinitialFocus, e->dssw.what_text, 
1883                                 NULL);
1884         }
1885
1886         if (! e->editor_is_up)
1887             {
1888             e->editor_is_up = True;
1889             set_editor_defaults(e, start, stop, show_notime);
1890         }
1891         add_all_appt(e);
1892         if (e->frame) XtPopup(e->frame, XtGrabNone);
1893         /* if (e->view_frame) XtPopup(e->view_frame, XtGrabNone); */
1894 }
1895
1896 extern void
1897 show_editor_view(Calendar *c, Glance glance) {
1898         Editor          *e = (Editor *)c->editor;
1899         Props_pu        *p = (Props_pu *)c->properties_pu;
1900
1901         if (!e->view_frame) {
1902                 e->cal = c;
1903                 e_build_view_popup(e);
1904         }
1905
1906         XtVaSetValues(e->view_form, XmNdefaultButton, e->view_cancel_button, NULL);
1907         XtVaSetValues(e->view_form, XmNcancelButton, e->view_cancel_button, NULL);
1908
1909
1910         if (build_editor_view(e, glance, False) <= 0) {
1911                 char *title = XtNewString(catgets(c->DT_catd, 1, 280,
1912                                 "Calendar : Error - Appointment List"));
1913                 char *text = XtNewString(catgets(c->DT_catd, 1, 281,
1914                                 "Sorry, no appointments to list.     "));
1915                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1916                 dialog_popup(e->cal->frame,
1917                         DIALOG_TITLE, title,
1918                         DIALOG_TEXT, text,
1919                         BUTTON_IDENT, 1, ident1,
1920                         DIALOG_IMAGE, p->xm_error_pixmap,
1921                         NULL);
1922                 XtFree(ident1);
1923                 XtFree(text);
1924                 XtFree(title);
1925                 XtUnmanageChild(e->view_form);
1926                 e->editor_view_is_up = False;
1927         } else {
1928                 if (!editor_view_showing(e))
1929                         ds_position_popup(c->frame, e->view_frame,
1930                                           DS_POPUP_LOR);
1931                 XtManageChild(e->view_form);
1932                 e->editor_view_is_up = True;
1933         }
1934         /* if (e->frame) XtPopup(e->frame, XtGrabNone); */
1935         if (e->view_frame) XtPopup(e->view_frame, XtGrabNone);
1936 }
1937 /*
1938 **  Function to set some editor defaults
1939 */
1940 static void
1941 set_editor_msg_defaults(Editor *e) {
1942         set_dssw_defaults(&e->dssw, e->cal->view->date, False);
1943         set_message(e->message_text, " ");
1944 }