Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / print.c
1 /* $XConsortium: print.c /main/18 1996/11/25 10:23:05 rswiston $ */
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 <csa.h>
14 #include <Xm/Xm.h>
15 #include <Xm/Form.h>
16 #include <Xm/LabelG.h>
17 #include <Xm/DialogS.h>
18 #include <Xm/Print.h>
19 #include <Xm/Protocols.h>
20 #include <Xm/PushBG.h>
21 #include <Xm/SeparatoG.h>
22 #include <Xm/SpinB.h>
23 #include <Xm/Text.h>
24 #include <Xm/TextF.h>
25 #include <Xm/ToggleB.h>
26 #include <Xm/ToggleBG.h>
27 #include <Xm/SashP.h>
28 #include <Xm/SSpinB.h>
29 #include <Xm/RowColumn.h>
30 #include <Dt/HourGlass.h>
31 #include "util.h"
32 #include "misc.h"
33 #include "props.h"
34 #include "props_pu.h"
35 #include "getdate.h"
36 #include "datefield.h"
37 #include "timeops.h"
38 #include "calendar.h"
39 #include "print.h"
40 #include "todo.h"
41 #include "help.h"
42
43 /* needed for view-specific print routines */
44 #include "dayglance.h"
45 #include "weekglance.h"
46 #include "monthglance.h"
47 #include "yearglance.h"
48
49 static char *printErrorTitle = "Calendar : Error - Print";
50 static char *setupErrorTitle = "Calendar : Error - Print Setup";
51 static char *pdmErrorText = "Print Dialog Manager error - setup failed.";
52
53 typedef struct {
54    /* widget handles */
55    Widget pdb;
56    Widget form;
57    Widget report_type_option;
58    Widget from_label;
59    Widget from_spin;
60    Widget from_day;
61    Widget from_month;
62    Widget from_year;
63    Widget to_label;
64    Widget to_spin;
65    Widget to_day;
66    Widget to_month;
67    Widget to_year;
68    Widget more_opts;
69 #ifdef GR_DEBUG
70    Widget debugToggle;
71 #endif
72
73    int    report_type;
74    Boolean setupDataValid;
75    DtPrintSetupData setupData;
76    Widget printShell;
77    Boolean badAllocError;
78 } _DtCmPrintData;
79
80 /*
81  * private function declarations
82  */
83 static void print_cb(Widget, XtPointer, XtPointer);
84 static void print_setup_cb(Widget, XtPointer, XtPointer);
85 static void close_print_display_cb(Widget, XtPointer, XtPointer);
86 static void cancel_cb(Widget, XtPointer, XtPointer);
87 static void pdm_notify_cb(Widget, XtPointer, XtPointer);
88 static void report_option_cb(Widget, XtPointer, XtPointer);
89 static void from_modify_verify_cb(Widget, XtPointer, XtPointer);
90 static void to_modify_verify_cb(Widget, XtPointer, XtPointer);
91 static void spin_field_changed_cb(Widget, XtPointer, XtPointer);
92 static void more_opts_cb(Widget, XtPointer, XtPointer);
93 static Tick pd_modify_day(Calendar *, int, Boolean);
94 static Tick pd_modify_month(Calendar *, int, Boolean);
95 static Tick pd_modify_year(Calendar *, int, Boolean);
96 static Boolean pd_set_start_date(Calendar *, Tick);
97 static Boolean pd_set_end_date(Calendar *, Tick);
98 static Boolean pd_set_max_start_date(Calendar *, Tick);
99 static Boolean pd_set_min_end_date(Calendar *, Tick);
100 static Boolean pd_set_report_type(Calendar *, int);
101 static Boolean pd_set_report_managed(Calendar *, int);
102 static Boolean pd_get_start_positions(Calendar *, int *, int *, int *);
103 static Boolean pd_get_end_positions(Calendar *, int *, int *, int *);
104 static void clearSetupData(_DtCmPrintData *);
105 static void createPrintShell(Calendar *);
106 static void report_error(Calendar *, char *, char *);
107
108 #ifdef GR_DEBUG
109 Boolean
110 inDebugMode(Calendar *c)
111 {
112   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
113   if (pd != (_DtCmPrintData *)NULL)
114     return XmToggleButtonGadgetGetState(pd->debugToggle);
115
116   return False;
117 }
118 #endif
119
120 static Boolean
121 pd_set_start_date(Calendar *c, Tick tick)
122 {
123   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
124   Props *p = (Props *)c->properties;
125   OrderingType ot = get_int_prop(p, CP_DATEORDERING);
126   SeparatorType st = get_int_prop(p, CP_DATESEPARATOR);
127   Arg args[5];
128   int nargs;
129
130   if (pd == (_DtCmPrintData *)NULL)
131     return False;
132
133   if (tick > get_eot())
134     tick = get_eot();
135
136   if (pd_get_report_type(c) == PR_WEEK_VIEW)
137   {
138     /* Week view - start at Monday. */
139     tick = first_dow(tick);
140   }
141
142   if (tick < get_bot())
143     tick = get_bot();
144
145   if (XtIsManaged(pd->from_day))
146   {
147     nargs = 0;
148     XtSetArg(args[nargs], XmNposition, dom(tick)); nargs++;
149     XtSetArg(args[nargs], XmNmaximumValue, monthlength(tick)); nargs++;
150     XtSetValues(pd->from_day, args, nargs);
151   }
152   if (XtIsManaged(pd->from_month))
153   {
154     XtSetArg(args[0], XmNposition, month(tick) - 1);
155     XtSetValues(pd->from_month, args, 1);
156   }
157   XtSetArg(args[0], XmNposition, year(tick));
158   XtSetValues(pd->from_year, args, 1);
159
160   return True;
161 }
162
163 static Boolean
164 pd_set_end_date(Calendar *c, Tick tick)
165 {
166   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
167   Props *p = (Props *)c->properties;
168   OrderingType ot = get_int_prop(p, CP_DATEORDERING);
169   SeparatorType st = get_int_prop(p, CP_DATESEPARATOR);
170   Arg args[5];
171   int nargs;
172
173   if (pd == (_DtCmPrintData *)NULL)
174     return False;
175
176   if (tick < get_bot())
177     tick = get_bot();
178
179   if (pd_get_report_type(c) == PR_WEEK_VIEW)
180   {
181     /* Week view - end on Sunday. */
182     tick = last_dow(tick);
183   }
184
185   if (tick > get_eot())
186     tick = get_eot();
187
188   if (XtIsManaged(pd->to_day))
189   {
190     nargs = 0;
191     XtSetArg(args[nargs], XmNposition, dom(tick)); nargs++;
192     XtSetArg(args[nargs], XmNmaximumValue, monthlength(tick)); nargs++;
193     XtSetValues(pd->to_day, args, nargs);
194   }
195   if (XtIsManaged(pd->to_month))
196   {
197     XtSetArg(args[0], XmNposition, month(tick) - 1);
198     XtSetValues(pd->to_month, args, 1);
199   }
200   XtSetArg(args[0], XmNposition, year(tick));
201   XtSetValues(pd->to_year, args, 1);
202
203   return True;
204 }
205
206 static Boolean
207 pd_set_max_start_date(Calendar *c, Tick tick)
208 {
209   Tick curTick = pd_get_start_date(c);
210
211   return (tick < curTick) ? pd_set_start_date(c, tick) : True;
212 }
213
214 static Boolean
215 pd_set_min_end_date(Calendar *c, Tick tick)
216 {
217   Tick curTick = pd_get_end_date(c);
218
219   return (tick > curTick) ? pd_set_end_date(c, tick) : True;
220 }
221
222 static Boolean
223 pd_set_report_type(Calendar *c, int reportType)
224 {
225   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
226   Widget optionMenu = (Widget)NULL;
227   Arg args[10];
228   int nargs;
229
230   if (pd == (_DtCmPrintData *)NULL)
231     return False;
232
233   if (reportType == pd->report_type)
234     return True;
235
236   nargs = 0;
237   XtSetArg(args[nargs], XmNsubMenuId, &optionMenu); nargs++;
238   XtGetValues(pd->report_type_option, args, nargs);
239
240   if (optionMenu != (Widget)NULL)
241   {
242     WidgetList optionChildren;
243     int nChildren = 0;
244
245     nargs = 0;
246     XtSetArg(args[nargs], XmNchildren, &optionChildren); nargs++;
247     XtSetArg(args[nargs], XmNnumChildren, &nChildren); nargs++;
248     XtGetValues(optionMenu, args, nargs);
249
250     if (nChildren > reportType)
251     {
252       nargs = 0;
253       XtSetArg(args[nargs], XmNmenuHistory,
254                optionChildren[reportType]); nargs++;
255       XtSetValues(pd->report_type_option, args, nargs);
256
257       return pd_set_report_managed(c, reportType);
258     }
259   }
260
261   return False;
262 }
263
264 static Boolean
265 pd_set_report_managed(Calendar *c, int reportType)
266 {
267   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
268   Arg args[10];
269   int nargs;
270
271   if (pd == (_DtCmPrintData *)NULL)
272     return False;
273
274   if (reportType == pd->report_type)
275     return True;
276
277   pd->report_type = reportType;
278
279   switch (reportType)
280   {
281   case PR_YEAR_VIEW:
282     XtManageChild(pd->from_year);
283     XtManageChild(pd->to_year);
284
285     XtUnmanageChild(pd->from_day);
286     XtUnmanageChild(pd->from_month);
287     XtUnmanageChild(pd->to_day);
288     XtUnmanageChild(pd->to_month);
289     break;
290
291   case PR_WEEK_VIEW:
292     XtManageChild(pd->from_year);
293     XtManageChild(pd->from_month);
294     XtManageChild(pd->from_day);
295     XtManageChild(pd->to_year);
296     XtManageChild(pd->to_month);
297     XtManageChild(pd->to_day);
298
299     nargs = 0;
300     XtSetArg(args[nargs], XmNeditable, False); nargs++;
301     XtSetArg(args[nargs], XmNcursorPositionVisible, False); nargs++;
302     XtSetValues(pd->from_day, args, nargs);
303     XtSetValues(pd->to_day, args, nargs);
304     break;
305
306   case PR_DAY_VIEW:
307   case PR_APPT_LIST:
308   case PR_TODO_LIST:
309     XtManageChild(pd->from_year);
310     XtManageChild(pd->from_month);
311     XtManageChild(pd->from_day);
312     XtManageChild(pd->to_year);
313     XtManageChild(pd->to_month);
314     XtManageChild(pd->to_day);
315
316     nargs = 0;
317     XtSetArg(args[nargs], XmNeditable, True); nargs++;
318     XtSetArg(args[nargs], XmNcursorPositionVisible, True); nargs++;
319     XtSetValues(pd->from_day, args, nargs);
320     XtSetValues(pd->to_day, args, nargs);
321     break;
322
323   default:
324   case PR_MONTH_VIEW:
325     XtManageChild(pd->from_year);
326     XtManageChild(pd->from_month);
327     XtManageChild(pd->to_year);
328     XtManageChild(pd->to_month);
329
330     XtUnmanageChild(pd->from_day);
331     XtUnmanageChild(pd->to_day);
332     break;
333   }
334
335   return True;
336 }
337
338 static Boolean
339 pd_get_start_positions(Calendar *c, int *m, int *d, int *y)
340 {
341   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
342   int dayPos = 1, monthPos = 0, yearPos;
343
344   if (pd == (_DtCmPrintData *)NULL)
345     return False;
346
347   if (XtIsManaged(pd->from_day))
348     XtVaGetValues(pd->from_day, XmNposition, &dayPos, NULL);
349   if (XtIsManaged(pd->from_month))
350     XtVaGetValues(pd->from_month, XmNposition, &monthPos, NULL);
351   XtVaGetValues(pd->from_year, XmNposition, &yearPos, NULL);
352
353   *m = monthPos;
354   *d = dayPos;
355   *y = yearPos;
356
357   return True;
358 }
359
360 static Boolean
361 pd_get_end_positions(Calendar *c, int *m, int *d, int *y)
362 {
363   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
364   int dayPos = 1, monthPos = 0, yearPos;
365
366   if (pd == (_DtCmPrintData *)NULL)
367     return False;
368
369   if (XtIsManaged(pd->to_day))
370     XtVaGetValues(pd->to_day, XmNposition, &dayPos, NULL);
371   if (XtIsManaged(pd->to_month))
372     XtVaGetValues(pd->to_month, XmNposition, &monthPos, NULL);
373   XtVaGetValues(pd->to_year, XmNposition, &yearPos, NULL);
374
375   *m = monthPos;
376   *d = dayPos;
377   *y = yearPos;
378
379   return True;
380 }
381
382 static void
383 from_modify_verify_cb(Widget w, XtPointer uDataP, XtPointer cbDataP)
384 {
385   Calendar *c = (Calendar *)uDataP;
386   XmSpinBoxCallbackStruct *cbStruct = (XmSpinBoxCallbackStruct *)cbDataP;
387   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
388   int newPos;
389   Tick newTick;
390
391   cbStruct->doit = False;
392
393   if (cbStruct->widget == pd->from_day)
394   {
395     newTick = pd_modify_day(c, cbStruct->reason, False);
396   }
397   else if (cbStruct->widget == pd->from_month)
398   {
399     newTick = pd_modify_month(c, cbStruct->reason, False);
400   }
401   else if (cbStruct->widget == pd->from_year)
402   {
403     newTick = pd_modify_year(c, cbStruct->reason, False);
404   }
405   else return;
406
407   if (pd_set_start_date(c, newTick) && pd_set_min_end_date(c, newTick))
408   {
409     int monthPos, dayPos, yearPos;
410
411     pd_get_start_positions(c, &monthPos, &dayPos, &yearPos);
412     if (cbStruct->widget == pd->from_day)
413       cbStruct->position = dayPos;
414     else if (cbStruct->widget == pd->from_month)
415       cbStruct->position = monthPos;
416     else cbStruct->position = yearPos;
417     cbStruct->doit = True;
418   }
419 }
420
421 static void
422 to_modify_verify_cb(Widget w, XtPointer uDataP, XtPointer cbDataP)
423 {
424   Calendar *c = (Calendar *)uDataP;
425   XmSpinBoxCallbackStruct *cbStruct = (XmSpinBoxCallbackStruct *)cbDataP;
426   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
427   Tick newTick;
428
429   cbStruct->doit = False;
430
431   if (cbStruct->widget == pd->to_day)
432   {
433     newTick = pd_modify_day(c, cbStruct->reason, True);
434   }
435   else if (cbStruct->widget == pd->to_month)
436   {
437     newTick = pd_modify_month(c, cbStruct->reason, True);
438   }
439   else if (cbStruct->widget == pd->to_year)
440   {
441     newTick = pd_modify_year(c, cbStruct->reason, True);
442   }
443   else return;
444
445   if (pd_set_end_date(c, newTick) && pd_set_max_start_date(c, newTick))
446   {
447     int monthPos, dayPos, yearPos;
448
449     pd_get_end_positions(c, &monthPos, &dayPos, &yearPos);
450     if (cbStruct->widget == pd->to_day)
451       cbStruct->position = dayPos;
452     else if (cbStruct->widget == pd->to_month)
453       cbStruct->position = monthPos;
454     else cbStruct->position = yearPos;
455     cbStruct->doit = True;
456   }
457 }
458
459 static void
460 spin_field_changed_cb(Widget field, XtPointer uData, XtPointer cbData)
461 {
462   char *newStr;
463   int curPos;
464   int newPos;
465   unsigned char sbcType;
466   int minValue;
467   int maxValue;
468   int nValues;
469   XmStringTable strings;
470   int cursorPosition;
471   Arg args[20];
472   int nargs;
473
474   nargs = 0;
475   XtSetArg(args[nargs], XmNspinBoxChildType, &sbcType); nargs++;
476   XtSetArg(args[nargs], XmNmaximumValue, &maxValue); nargs++;
477   XtSetArg(args[nargs], XmNminimumValue, &minValue); nargs++;
478   XtSetArg(args[nargs], XmNnumValues, &nValues); nargs++;
479   XtSetArg(args[nargs], XmNposition, &curPos); nargs++;
480   XtSetArg(args[nargs], XmNvalues, &strings); nargs++;
481   XtSetArg(args[nargs], XmNvalue, &newStr); nargs++;
482   XtSetArg(args[nargs], XmNcursorPosition, &cursorPosition); nargs++;
483   XtGetValues(field, args, nargs);
484
485   newPos = curPos;
486   if (sbcType == XmSTRING)
487   {
488     XmString xmString = XmStringCreateLocalized(newStr);
489
490     for (newPos = 0; newPos < nValues; newPos++)
491     {
492       if (XmStringCompare(xmString, strings[newPos]))
493         break;
494     }
495
496     if (newPos >= nValues)
497       newPos = curPos;
498
499     XmStringFree(xmString);
500   }
501   else if (sbcType == XmNUMERIC)
502   {
503     newPos = atoi(newStr);
504
505     if ((newPos < minValue) ||
506         (newPos > maxValue))
507       newPos = curPos;
508   }
509
510   if (newPos != curPos)
511   {
512     nargs = 0;
513     XtSetArg(args[nargs], XmNposition, newPos); nargs++;
514     XtSetValues(field, args, nargs);
515
516     /* After the above does its thing, restore original cursor position. */
517     nargs = 0;
518     XtSetArg(args[nargs], XmNcursorPosition, cursorPosition); nargs++;
519     XtSetValues(field, args, nargs);
520   }
521
522   XtFree(newStr);
523 }
524
525 static void
526 more_opts_cb(Widget w, XtPointer uData, XtPointer cbData)
527 {
528   Calendar *c = (Calendar *)uData;
529   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
530
531   _DtTurnOnHourGlass(c->frame);
532   _DtTurnOnHourGlass(pd->pdb);
533
534   show_print_props_pu(c);
535
536   _DtTurnOffHourGlass(pd->pdb);
537   _DtTurnOffHourGlass(c->frame);
538 }
539
540 static Tick
541 pd_modify_day(Calendar *c, int reason, Boolean isTo)
542 {
543   int monthPos, dayPos, yearPos;
544   int maxDay;
545   Tick tmpTick;
546   Tick curTick;
547   Tick newTick;
548   int reportType = pd_get_report_type(c);
549
550   if (isTo)
551   {
552     if (!pd_get_end_positions(c, &monthPos, &dayPos, &yearPos))
553       return 0;
554   }
555   else
556   {
557     if (!pd_get_start_positions(c, &monthPos, &dayPos, &yearPos))
558       return 0;
559   }
560
561   switch (reason)
562   {
563   case XmCR_SPIN_NEXT:
564     tmpTick = monthdayyear(monthPos + 1, 1, yearPos);
565     maxDay = monthlength(tmpTick);
566     if ((dayPos == 1) || (dayPos > maxDay))
567       dayPos = maxDay;
568     else dayPos--;
569     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
570     newTick = (reportType == PR_WEEK_VIEW) ?
571       nextweek(curTick) : nextday(curTick);
572     break;
573
574   case XmCR_SPIN_PRIOR:
575     tmpTick = monthdayyear(monthPos + 1, 1, yearPos);
576     maxDay = monthlength(tmpTick);
577     if (dayPos >= maxDay)
578       dayPos = 1;
579     else dayPos++;
580     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
581     newTick = (reportType == PR_WEEK_VIEW) ?
582       prevweek(curTick) : prevday(curTick);
583     break;
584
585   default:
586   case XmCR_SPIN_FIRST:
587     newTick = monthdayyear(monthPos + 1, 1, yearPos);
588     if (reportType == PR_WEEK_VIEW)
589     {
590       if (isTo)
591       {
592         /* We want the first Sunday in the month. */
593         newTick = last_dow(newTick);
594       }
595       else
596       {
597         /* We want the first Monday in the month. */
598         int dayOffset = (dow(newTick) + 6) % 7;
599
600         if (dayOffset > 0)
601           newTick = next_ndays(newTick, 7 - dayOffset);
602       }
603     }
604     break;
605
606   case XmCR_SPIN_LAST:
607     curTick = monthdayyear(monthPos + 1, 1, yearPos);
608     newTick = last_dom(curTick);
609     if (reportType == PR_WEEK_VIEW)
610     {
611       if (isTo)
612       {
613         /* We want the last Sunday in the month. */
614         int dayOffset = dow(newTick);
615
616         if (dayOffset > 0)
617           newTick = last_ndays(newTick, dayOffset);
618       }
619       else
620       {
621         /* We want the last Monday in the month. */
622         newTick = first_dow(newTick);
623       }
624     }
625     break;
626   }
627
628   return newTick;
629 }
630
631 static Tick
632 pd_modify_month(Calendar *c, int reason, Boolean isTo)
633 {
634   int monthPos, dayPos, yearPos;
635   int maxDay;
636   Tick tmpTick;
637   Tick curTick;
638   Tick newTick;
639   int reportType = pd_get_report_type(c);
640
641   if (isTo)
642   {
643     if (!pd_get_end_positions(c, &monthPos, &dayPos, &yearPos))
644       return 0;
645   }
646   else
647   {
648     if (!pd_get_start_positions(c, &monthPos, &dayPos, &yearPos))
649       return 0;
650   }
651
652   switch (reason)
653   {
654   case XmCR_SPIN_NEXT:
655     if (monthPos == 0)
656       monthPos = 11;
657     else monthPos--;
658
659     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
660     if (reportType == PR_WEEK_VIEW)
661       newTick = next_ndays(curTick, 4 * 7);
662     else
663     {
664       tmpTick = nextmonth(curTick);
665       maxDay = monthlength(tmpTick);
666       if (dayPos > maxDay)
667         dayPos = maxDay;
668       newTick = monthdayyear(month(tmpTick), dayPos, year(tmpTick));
669     }
670     break;
671
672   case XmCR_SPIN_PRIOR:
673     if (monthPos == 11)
674       monthPos = 0;
675     else monthPos++;
676
677     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
678     if (reportType == PR_WEEK_VIEW)
679       newTick = last_ndays(curTick, 4 * 7);
680     else
681     {
682       /* ... There is no prevmonth()! ... */
683       tmpTick = prev_nmonth(curTick, 1);
684       maxDay = monthlength(tmpTick);
685       if (dayPos > maxDay)
686         dayPos = maxDay;
687       newTick = monthdayyear(month(tmpTick), dayPos, year(tmpTick));
688     }
689     break;
690
691   default:
692   case XmCR_SPIN_FIRST:
693     newTick = monthdayyear(1, 1, yearPos);
694     if (reportType == PR_WEEK_VIEW)
695     {
696       if (isTo)
697       {
698         /* We want the first Sunday in the month. */
699         newTick = last_dow(newTick);
700       }
701       else
702       {
703         /* We want the first Monday in the month. */
704         int dayOffset = (dow(newTick) + 6) % 7;
705
706         if (dayOffset > 0)
707           newTick = next_ndays(newTick, 7 - dayOffset);
708       }
709     }
710     break;
711
712   case XmCR_SPIN_LAST:
713     newTick = monthdayyear(12, 31, yearPos);
714     if (reportType == PR_WEEK_VIEW)
715     {
716       if (isTo)
717       {
718         /* We want the last Sunday in the month. */
719         int dayOffset = dow(newTick);
720
721         if (dayOffset > 0)
722           newTick = last_ndays(newTick, dayOffset);
723       }
724       else
725       {
726         /* We want the last Monday in the month. */
727         newTick = first_dow(newTick);
728       }
729     }
730     break;
731   }
732
733   return newTick;
734 }
735
736 static Tick
737 pd_modify_year(Calendar *c, int reason, Boolean isTo)
738 {
739   int monthPos, dayPos, yearPos;
740   int maxDay;
741   Tick tmpTick;
742   Tick curTick;
743   Tick newTick;
744   int reportType = pd_get_report_type(c);
745
746   if (isTo)
747   {
748     if (!pd_get_end_positions(c, &monthPos, &dayPos, &yearPos))
749       return 0;
750   }
751   else
752   {
753     if (!pd_get_start_positions(c, &monthPos, &dayPos, &yearPos))
754       return 0;
755   }
756
757   switch (reason)
758   {
759   case XmCR_SPIN_NEXT:
760     yearPos--;
761
762     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
763     if (reportType == PR_WEEK_VIEW)
764       newTick = next_ndays(curTick, 52 * 7);
765     else
766     {
767       tmpTick = monthdayyear(monthPos + 1, 1, yearPos + 1);
768       maxDay = monthlength(tmpTick);
769       if (dayPos > maxDay)
770         dayPos = maxDay;
771       newTick = monthdayyear(monthPos + 1, dayPos, yearPos + 1);
772     }
773     break;
774
775   case XmCR_SPIN_PRIOR:
776     yearPos++;
777
778     curTick = monthdayyear(monthPos + 1, dayPos, yearPos);
779     if (reportType == PR_WEEK_VIEW)
780       newTick = last_ndays(curTick, 52 * 7);
781     else
782     {
783       tmpTick = monthdayyear(monthPos + 1, 1, yearPos - 1);
784       maxDay = monthlength(tmpTick);
785       if (dayPos > maxDay)
786         dayPos = maxDay;
787       newTick = monthdayyear(monthPos + 1, dayPos, yearPos - 1);
788     }
789     break;
790
791   default:
792   case XmCR_SPIN_FIRST:
793     yearPos = year(get_bot());
794     tmpTick = monthdayyear(monthPos + 1, 1, yearPos);
795     maxDay = monthlength(tmpTick);
796     if (dayPos > maxDay)
797       dayPos = maxDay;
798     newTick = monthdayyear(monthPos + 1, dayPos, yearPos);
799     break;
800
801   case XmCR_SPIN_LAST:
802     yearPos = year(get_eot());
803     tmpTick = monthdayyear(monthPos + 1, 1, yearPos);
804     maxDay = monthlength(tmpTick);
805     if (dayPos > maxDay)
806       dayPos = maxDay;
807     newTick = monthdayyear(monthPos + 1, dayPos, yearPos);
808     break;
809   }
810
811   return newTick;
812 }
813
814 /*
815  * post_print_dialog()
816  *
817  * Create and display the Print dialog.
818  */
819 void
820 post_print_dialog(
821         Calendar *c)
822 {
823   _DtCmPrintData *pd;
824
825   create_print_dialog(c);
826
827   /* display the dialog on-screen */
828   if ((pd = (_DtCmPrintData *)c->print_data) != (_DtCmPrintData *)NULL)
829   {
830     if (!XtIsManaged(pd->pdb))
831       XtManageChild(pd->pdb);
832     else XRaiseWindow(XtDisplay(pd->pdb),
833                       XtWindow(XtParent(pd->pdb)));
834   }
835 }
836
837 static void
838 clearSetupData(_DtCmPrintData *pd)
839 {
840   if (pd->setupDataValid)
841   {
842     DtPrintFreeSetupData(&pd->setupData);
843     pd->setupDataValid = False;
844   }
845
846   memset(&pd->setupData, 0, sizeof(DtPrintSetupData));
847 }
848
849 static void
850 createPrintShell(Calendar *c)
851 {
852   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
853
854 #ifdef GR_DEBUG
855   if (inDebugMode(c))
856   {
857     if (pd->printShell != (Widget)NULL)
858       XtDestroyWidget(pd->printShell);
859
860     pd->printShell = XmCreateDialogShell(c->frame, "Print",
861                                          0, NULL);
862   }
863   else
864 #endif
865   if (pd->printShell == (Widget)NULL)
866   {
867     pd->printShell =
868       XmPrintSetup(pd->pdb,
869                    XpGetScreenOfContext(pd->setupData.print_display,
870                                         pd->setupData.print_context),
871                    "Print", NULL, 0);
872
873     XtAddCallback(pd->printShell, XmNpdmNotificationCallback,
874                   pdm_notify_cb, (XtPointer)c);
875   }
876 }
877
878 void
879 create_print_dialog(Calendar *c)
880 {
881         XmString         xmstr, day_view, week_view, month_view,
882                          year_view, appt_list, todo_list, view;
883         _DtCmPrintData  *pd;
884         char             fnamebuf[BUFSIZ];
885         char             *print_file;
886         char             *print_dir;
887         char             *title;
888         Arg              args[20];
889         int              nargs;
890         XmString         abbrevMonths[12];
891         int              maxMonthLen;
892         int              i;
893         int              reportType;
894         Widget           helpButton;
895
896         if ((pd = (_DtCmPrintData *)c->print_data) == NULL)
897         {
898           c->print_data = (caddr_t)XtMalloc(sizeof(_DtCmPrintData));
899           pd = (_DtCmPrintData *) c->print_data;
900
901           /* Initialize filename to dir+filename from props */
902           print_file = get_char_prop((Props *)c->properties,CP_PRINTFILENAME);
903           if (!print_file)
904             print_file = "";
905           print_dir = get_char_prop((Props *)c->properties,CP_PRINTDIRNAME);
906           if (!print_dir)
907             print_dir = "";
908           sprintf(fnamebuf, "%s/%s", print_dir, print_file);
909
910           title = XtNewString(catgets(c->DT_catd, 1, 728, "Calendar : Print"));
911           nargs = 0;
912           XtSetArg(args[nargs], XmNtitle, title); nargs++;
913           XtSetArg(args[nargs], XmNdeleteResponse, XmUNMAP); nargs++;
914           XtSetArg(args[nargs], DtNfileName, fnamebuf); nargs++;
915           XtSetArg(args[nargs], XmNautoUnmanage, False); nargs++;
916           XtSetArg(args[nargs], XmNdeleteResponse, XmDO_NOTHING); nargs++;
917           pd->pdb = DtCreatePrintSetupDialog(c->frame, "Calendar - Print",
918                                              args, nargs);
919           XtFree(title);
920
921           setup_quit_handler(XtParent(pd->pdb), cancel_cb, (XtPointer)c);
922
923           XtAddCallback(pd->pdb, DtNcancelCallback,
924                         cancel_cb, (XtPointer)c);
925           XtAddCallback(pd->pdb, DtNprintCallback,
926                         print_cb, (XtPointer)c);
927           XtAddCallback(pd->pdb, DtNclosePrintDisplayCallback,
928                         close_print_display_cb, (XtPointer)c);
929           XtAddCallback(pd->pdb, DtNsetupCallback,
930                         print_setup_cb, (XtPointer)c);
931
932           helpButton = XtNameToWidget(pd->pdb, "Help");
933           if (helpButton != (Widget)NULL)
934             XtAddCallback(helpButton, XmNactivateCallback,
935                           help_cb, (XtPointer)PRINT_HELP_BUTTON);
936           XtAddCallback(pd->pdb, XmNhelpCallback,
937                         help_cb, (XtPointer)PRINT_HELP_BUTTON);
938
939           nargs = 0;
940           XtSetArg(args[nargs], XmNfractionBase, 3); nargs++;
941           pd->form = XmCreateForm(pd->pdb, "RangeForm", args, nargs);
942
943           view = XmStringCreateLocalized(
944                         catgets(c->DT_catd, 1, 976, "Report Type:"));
945           day_view = XmStringCreateLocalized(
946                         catgets(c->DT_catd, 1, 977, "Day View"));
947           week_view = XmStringCreateLocalized(
948                         catgets(c->DT_catd, 1, 978, "Week View"));
949           month_view = XmStringCreateLocalized(
950                         catgets(c->DT_catd, 1, 979, "Month View"));
951           year_view = XmStringCreateLocalized(
952                         catgets(c->DT_catd, 1, 980, "Year View"));
953           appt_list = XmStringCreateLocalized(
954                         catgets(c->DT_catd, 1, 981, "Appointment List"));
955           todo_list = XmStringCreateLocalized(
956                         catgets(c->DT_catd, 1, 982, "To Do List"));
957
958           /*
959            * remember - this returns a RowColumn widget!
960            */
961           pd->report_type = PR_DAY_VIEW;
962           pd->report_type_option = XmVaCreateSimpleOptionMenu(pd->form,
963                 "TypeOptionMenu", view, NULL,
964                 pd->report_type, report_option_cb,
965                 XmVaPUSHBUTTON,         day_view, NULL, NULL, NULL,
966                 XmVaPUSHBUTTON,         week_view, NULL, NULL, NULL,
967                 XmVaPUSHBUTTON,         month_view, NULL, NULL, NULL,
968                 XmVaPUSHBUTTON,         year_view, NULL, NULL, NULL,
969                 XmVaPUSHBUTTON,         appt_list, NULL, NULL, NULL,
970                 XmVaPUSHBUTTON,         todo_list, NULL, NULL, NULL,
971                 XmNorientation,         XmVERTICAL,
972                 XmNtopAttachment,       XmATTACH_FORM,
973                 XmNtopOffset,           10,
974                 XmNleftAttachment,      XmATTACH_POSITION,
975                 XmNleftPosition,        1,
976                 XmNleftOffset,          5,
977                 XmNmarginWidth,         0,
978                 XmNnavigationType,      XmTAB_GROUP,
979                 NULL);
980           XtManageChild(pd->report_type_option);
981
982           XmStringFree(day_view);
983           XmStringFree(week_view);
984           XmStringFree(month_view);
985           XmStringFree(year_view);
986           XmStringFree(appt_list);
987           XmStringFree(todo_list);
988           XmStringFree(view);
989
990           xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1,
991                                                   731, "From:"));
992           pd->from_label = XtVaCreateWidget("FromLabel",
993                 xmLabelGadgetClass,
994                 pd->form,
995                 XmNlabelString,         xmstr,
996                 XmNleftAttachment,      XmATTACH_POSITION,
997                 XmNleftPosition,        0,
998                 XmNleftOffset,          10,
999                 XmNtopAttachment,       XmATTACH_OPPOSITE_WIDGET,
1000                 XmNtopWidget,           pd->report_type_option,
1001                 XmNtopOffset,           0,
1002                 NULL);
1003           XmStringFree(xmstr);
1004           XtManageChild(pd->from_label);
1005
1006           nargs = 0;
1007           XtSetArg(args[nargs], XmNleftAttachment,
1008                    XmATTACH_OPPOSITE_WIDGET); nargs++;
1009           XtSetArg(args[nargs], XmNleftWidget, pd->from_label); nargs++;
1010           XtSetArg(args[nargs], XmNleftOffset, 0); nargs++;
1011           XtSetArg(args[nargs], XmNtopAttachment, XmATTACH_WIDGET); nargs++;
1012           XtSetArg(args[nargs], XmNtopWidget, pd->from_label); nargs++;
1013           XtSetArg(args[nargs], XmNtopOffset, 4); nargs++;
1014           XtSetArg(args[nargs], XmNshadowThickness, 1); nargs++;
1015           pd->from_spin = XmCreateSpinBox(pd->form, "FromSpinBox",
1016                                           args, nargs);
1017           XtAddCallback(pd->from_spin, XmNmodifyVerifyCallback,
1018                         from_modify_verify_cb, (XtPointer)c);
1019
1020           nargs = 0;
1021           XtSetArg(args[nargs], XmNspinBoxChildType, XmNUMERIC); nargs++;
1022           XtSetArg(args[nargs], XmNminimumValue, 1); nargs++;
1023           XtSetArg(args[nargs], XmNmaximumValue, 31); nargs++;
1024           XtSetArg(args[nargs], XmNcolumns, 2); nargs++;
1025           XtSetArg(args[nargs], XmNmaxLength, 2); nargs++;
1026           XtSetArg(args[nargs], XmNposition, 1); nargs++;
1027           pd->from_day = XmCreateTextField(pd->from_spin, "FromDay",
1028                                            args, nargs);
1029           XtAddCallback(pd->from_day, XmNvalueChangedCallback,
1030                         spin_field_changed_cb, (XtPointer)NULL);
1031           XtManageChild(pd->from_day);
1032
1033           maxMonthLen = 0;
1034           for (i = 0; i < 12; i++)
1035           {
1036             abbrevMonths[i] = XmStringCreateLocalized(months2[i + 1]);
1037             if (cm_strlen(months2[i + 1]) > maxMonthLen)
1038               maxMonthLen = cm_strlen(months2[i + 1]);
1039           }
1040           nargs = 0;
1041           XtSetArg(args[nargs], XmNspinBoxChildType, XmSTRING); nargs++;
1042           XtSetArg(args[nargs], XmNnumValues, 12); nargs++;
1043           XtSetArg(args[nargs], XmNvalues, abbrevMonths); nargs++;
1044           XtSetArg(args[nargs], XmNcolumns, maxMonthLen); nargs++;
1045           XtSetArg(args[nargs], XmNmaxLength, maxMonthLen); nargs++;
1046           XtSetArg(args[nargs], XmNposition, 0); nargs++;
1047           pd->from_month = XmCreateTextField(pd->from_spin, "FromMonth",
1048                                              args, nargs);
1049           XtAddCallback(pd->from_month, XmNvalueChangedCallback,
1050                         spin_field_changed_cb, (XtPointer)NULL);
1051           XtManageChild(pd->from_month);
1052
1053           nargs = 0;
1054           XtSetArg(args[nargs], XmNspinBoxChildType, XmNUMERIC); nargs++;
1055           XtSetArg(args[nargs], XmNminimumValue,
1056                    year(get_bot())); nargs++;
1057           XtSetArg(args[nargs], XmNmaximumValue,
1058                    year(get_eot())); nargs++;
1059           XtSetArg(args[nargs], XmNcolumns, 4); nargs++;
1060           XtSetArg(args[nargs], XmNmaxLength, 4); nargs++;
1061           XtSetArg(args[nargs], XmNposition,
1062                    year(get_bot())); nargs++;
1063           XtSetArg(args[nargs], XmNwrap, False); nargs++;
1064           pd->from_year = XmCreateTextField(pd->from_spin, "FromYear",
1065                                             args, nargs);
1066           XtAddCallback(pd->from_year, XmNvalueChangedCallback,
1067                         spin_field_changed_cb, (XtPointer)NULL);
1068           XtManageChild(pd->from_year);
1069           XtManageChild(pd->from_spin);
1070
1071           xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1,
1072                                                   732, "To:"));
1073           pd->to_label = XtVaCreateWidget("ToLabel",
1074                 xmLabelGadgetClass,
1075                 pd->form,
1076                 XmNlabelString,         xmstr,
1077                 XmNleftAttachment,      XmATTACH_POSITION,
1078                 XmNleftPosition,        2,
1079                 XmNleftOffset,          10,
1080                 XmNtopAttachment,       XmATTACH_OPPOSITE_WIDGET,
1081                 XmNtopWidget,           pd->report_type_option,
1082                 XmNtopOffset,           0,
1083                 NULL);
1084           XmStringFree(xmstr);
1085           XtManageChild(pd->to_label);
1086
1087           nargs = 0;
1088           XtSetArg(args[nargs], XmNleftAttachment,
1089                    XmATTACH_OPPOSITE_WIDGET); nargs++;
1090           XtSetArg(args[nargs], XmNleftWidget, pd->to_label); nargs++;
1091           XtSetArg(args[nargs], XmNleftOffset, 0); nargs++;
1092           XtSetArg(args[nargs], XmNtopAttachment, XmATTACH_WIDGET); nargs++;
1093           XtSetArg(args[nargs], XmNtopWidget, pd->to_label); nargs++;
1094           XtSetArg(args[nargs], XmNtopOffset, 4); nargs++;
1095           XtSetArg(args[nargs], XmNshadowThickness, 1); nargs++;
1096           pd->to_spin = XmCreateSpinBox(pd->form, "ToSpinBox",
1097                                         args, nargs);
1098           XtAddCallback(pd->to_spin, XmNmodifyVerifyCallback,
1099                         to_modify_verify_cb, (XtPointer)c);
1100
1101           nargs = 0;
1102           XtSetArg(args[nargs], XmNspinBoxChildType, XmNUMERIC); nargs++;
1103           XtSetArg(args[nargs], XmNminimumValue, 1); nargs++;
1104           XtSetArg(args[nargs], XmNmaximumValue, 31); nargs++;
1105           XtSetArg(args[nargs], XmNcolumns, 2); nargs++;
1106           XtSetArg(args[nargs], XmNmaxLength, 2); nargs++;
1107           XtSetArg(args[nargs], XmNposition, 1); nargs++;
1108           pd->to_day = XmCreateTextField(pd->to_spin, "ToDay",
1109                                            args, nargs);
1110           XtAddCallback(pd->to_day, XmNvalueChangedCallback,
1111                         spin_field_changed_cb, (XtPointer)NULL);
1112           XtManageChild(pd->to_day);
1113
1114           nargs = 0;
1115           XtSetArg(args[nargs], XmNspinBoxChildType, XmSTRING); nargs++;
1116           XtSetArg(args[nargs], XmNnumValues, 12); nargs++;
1117           XtSetArg(args[nargs], XmNvalues, abbrevMonths); nargs++;
1118           XtSetArg(args[nargs], XmNcolumns, maxMonthLen); nargs++;
1119           XtSetArg(args[nargs], XmNmaxLength, maxMonthLen); nargs++;
1120           XtSetArg(args[nargs], XmNposition, 0); nargs++;
1121           pd->to_month = XmCreateTextField(pd->to_spin, "ToMonth",
1122                                            args, nargs);
1123           XtAddCallback(pd->to_month, XmNvalueChangedCallback,
1124                         spin_field_changed_cb, (XtPointer)NULL);
1125           XtManageChild(pd->to_month);
1126           for (i = 0; i < 12; i++)
1127             XmStringFree(abbrevMonths[i]);
1128
1129           nargs = 0;
1130           XtSetArg(args[nargs], XmNspinBoxChildType, XmNUMERIC); nargs++;
1131           XtSetArg(args[nargs], XmNminimumValue,
1132                    year(get_bot())); nargs++;
1133           XtSetArg(args[nargs], XmNmaximumValue,
1134                    year(get_eot())); nargs++;
1135           XtSetArg(args[nargs], XmNcolumns, 4); nargs++;
1136           XtSetArg(args[nargs], XmNmaxLength, 4); nargs++;
1137           XtSetArg(args[nargs], XmNposition,
1138                    year(get_bot())); nargs++;
1139           XtSetArg(args[nargs], XmNwrap, False); nargs++;
1140           pd->to_year = XmCreateTextField(pd->to_spin, "ToYear",
1141                                           args, nargs);
1142           XtAddCallback(pd->to_year, XmNvalueChangedCallback,
1143                         spin_field_changed_cb, (XtPointer)NULL);
1144           XtManageChild(pd->to_year);
1145           XtManageChild(pd->to_spin);
1146
1147           xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1,
1148                                                   679, "More..."));
1149           nargs = 0;
1150           XtSetArg(args[nargs], XmNlabelString, xmstr); nargs++;
1151           XtSetArg(args[nargs], XmNrightAttachment, XmATTACH_FORM); nargs++;
1152           XtSetArg(args[nargs], XmNrightOffset, 10); nargs++;
1153           XtSetArg(args[nargs], XmNtopAttachment, XmATTACH_WIDGET); nargs++;
1154           XtSetArg(args[nargs], XmNtopWidget, pd->to_spin); nargs++;
1155           XtSetArg(args[nargs], XmNtopOffset, 10); nargs++;
1156           pd->more_opts = XmCreatePushButtonGadget(pd->form, "MoreOpts",
1157                                                    args, nargs);
1158           XtAddCallback(pd->more_opts, XmNactivateCallback,
1159                         more_opts_cb, (XtPointer)c);
1160           XtManageChild(pd->more_opts);
1161           XmStringFree(xmstr);
1162
1163 #ifdef GR_DEBUG
1164           nargs = 0;
1165           XtSetArg(args[nargs], XmNleftAttachment, XmATTACH_FORM); nargs++;
1166           XtSetArg(args[nargs], XmNleftOffset, 10); nargs++;
1167           XtSetArg(args[nargs], XmNtopAttachment,
1168                    XmATTACH_OPPOSITE_WIDGET); nargs++;
1169           XtSetArg(args[nargs], XmNtopWidget, pd->more_opts); nargs++;
1170           XtSetArg(args[nargs], XmNtopOffset, 10); nargs++;
1171           pd->debugToggle = XmCreateToggleButtonGadget(pd->form, "Debug Mode",
1172                                                        args, nargs);
1173           XtManageChild(pd->debugToggle);
1174 #endif
1175
1176           XtManageChild(pd->form);
1177
1178           pd->setupDataValid = False;
1179           clearSetupData(pd);
1180           pd->printShell = (Widget)NULL;
1181           pd->badAllocError = False;
1182         }
1183
1184         /* Set report type and dates according to current view/day. */
1185         switch (c->view->glance) {
1186         case dayGlance : reportType = PR_DAY_VIEW; break;
1187         case weekGlance : reportType = PR_WEEK_VIEW; break;
1188         case yearGlance : reportType = PR_YEAR_VIEW; break;
1189         default:
1190         case monthGlance : reportType = PR_MONTH_VIEW; break;
1191         }
1192
1193         pd_set_report_type(c, reportType);
1194
1195         pd_set_start_date(c, c->view->date);
1196         pd_set_end_date(c, c->view->date);
1197 }
1198
1199 /*
1200  * Close dialog
1201  */
1202 static void
1203 cancel_cb(Widget w, XtPointer data, XtPointer ignore)
1204 {
1205   Calendar *c = (Calendar *)data;
1206   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1207
1208   XtUnmanageChild(pd->pdb);
1209 }
1210
1211 static void
1212 report_error(Calendar *c, char *title, char *errText)
1213 {
1214   Props_pu *pu = (Props_pu *)c->properties_pu;
1215   char *label;
1216
1217   label = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1218
1219   dialog_popup(c->frame,
1220                DIALOG_TITLE, title,
1221                DIALOG_TEXT, errText,
1222                BUTTON_IDENT, 1, label,
1223                DIALOG_IMAGE, pu->xm_error_pixmap,
1224                NULL);
1225
1226   XtFree(label);
1227 }
1228
1229 static void
1230 pdm_notify_cb(Widget w, XtPointer uData, XtPointer cbData)
1231 {
1232   XmPrintShellCallbackStruct *cbStruct =
1233     (XmPrintShellCallbackStruct *)cbData;
1234   Calendar *c = (Calendar *)uData;
1235   char *errText = (char *)NULL;
1236   char *title;
1237
1238   switch (cbStruct->reason)
1239   {
1240   case XmCR_PDM_NONE:
1241   case XmCR_PDM_START_ERROR:
1242   case XmCR_PDM_EXIT_ERROR:
1243     errText = XtNewString(catgets(c->DT_catd, 1, 1112, pdmErrorText));
1244     break;
1245
1246   default:
1247     break;
1248   }
1249
1250   if (errText)
1251   {
1252     title = XtNewString(catgets(c->DT_catd, 1, 1111, setupErrorTitle));
1253
1254     report_error(c, title, errText);
1255
1256     XtFree(title);
1257     XtFree(errText);
1258   }
1259 }
1260
1261 /*
1262  * Called when print dialog box's print display is closed.
1263  */
1264 static void
1265 close_print_display_cb(Widget w, XtPointer uData, XtPointer cbData)
1266 {
1267   Calendar *c = (Calendar *)uData;
1268   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1269
1270   if (pd != (_DtCmPrintData *)NULL)
1271   {
1272     /* Destroy printShell associated with Display, if any. */
1273     if (pd->printShell != (Widget)NULL)
1274     {
1275       XtDestroyWidget(pd->printShell);
1276       pd->printShell = (Widget)NULL;
1277     }
1278
1279     clearSetupData(pd);
1280   }
1281 }
1282
1283 /*
1284  * Print callback: do the deed!
1285  */
1286 static void
1287 print_cb(Widget w, XtPointer data, XtPointer cbDataP)
1288 {
1289    Calendar *c = (Calendar *)data;
1290    _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1291    DtPrintSetupCallbackStruct *cbStruct =
1292      (DtPrintSetupCallbackStruct *)cbDataP;
1293
1294    clearSetupData(pd);
1295    DtPrintCopySetupData(&pd->setupData, cbStruct->print_data);
1296    pd->setupDataValid = True;
1297
1298    _DtTurnOnHourGlass(c->frame);
1299    print_report(c);
1300    _DtTurnOffHourGlass(c->frame);
1301
1302    /* Leave setupDataValid=True for quick print! */
1303 }
1304
1305 static void
1306 print_setup_cb(Widget w, XtPointer uData, XtPointer cbData)
1307 {
1308   Calendar *c = (Calendar *)uData;
1309   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1310   DtPrintSetupCallbackStruct *cbStruct =
1311     (DtPrintSetupCallbackStruct *)cbData;
1312
1313   clearSetupData(pd);
1314   DtPrintCopySetupData(&pd->setupData, cbStruct->print_data);
1315   pd->setupDataValid = True;
1316
1317 #ifdef GR_DEBUG
1318   /* Force debug mode off. */
1319   if (inDebugMode(c))
1320     XmToggleButtonGadgetSetState(pd->debugToggle, False, False);
1321 #endif
1322
1323   createPrintShell(c);
1324
1325   if (XmPrintPopupPDM(pd->printShell, w) != XmPDM_NOTIFY_SUCCESS)
1326   {
1327     char *errText = XtNewString(catgets(c->DT_catd, 1, 1112,
1328                                         pdmErrorText));
1329     char *title = XtNewString(catgets(c->DT_catd, 1, 1111, setupErrorTitle));
1330
1331     report_error(c, title, errText);
1332
1333     XtFree(title);
1334     XtFree(errText);
1335   }
1336
1337   clearSetupData(pd);
1338 }
1339
1340 /*
1341  * print_report: dispatch the view-specific output routine
1342  */
1343 void
1344 print_report(Calendar *c)
1345 {
1346   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1347   Props         *p = (Props *) c->properties;
1348   Props_pu      *pu = (Props_pu *) c->properties_pu;
1349   int           r = pd_get_report_type(c);
1350   OrderingType  ot = get_int_prop(p, CP_DATEORDERING);
1351   SeparatorType st = get_int_prop(p, CP_DATESEPARATOR);
1352   Tick          start_date = pd_get_start_date(c);
1353   Tick          end_date = pd_get_end_date(c);
1354   char *text = (char *)NULL;
1355
1356   if ((start_date == DATE_BBOT) || (end_date == DATE_BBOT) || 
1357       (start_date == DATE_AEOT) || (end_date == DATE_BBOT))
1358   {
1359     text = XtNewString(catgets(c->DT_catd, 1, 892,
1360         "The dates for printing must be between 1969 and 2038."));
1361   }
1362   else if (start_date <= 0)
1363   {
1364     text = XtNewString(catgets(c->DT_catd, 1, 894,
1365                                "Malformed \"From\" date"));
1366   }
1367   else if (end_date <= 0)
1368   {
1369     text = XtNewString(catgets(c->DT_catd, 1, 896,
1370                                "Malformed \"To\" date"));
1371   }
1372   else if (start_date > end_date)
1373   {
1374     text = XtNewString(catgets(c->DT_catd, 1, 898,
1375 "The \"To\" date for printing must be after the \"From\" date for printing"));
1376   }
1377
1378   if (text)
1379   {
1380     char *title = XtNewString(catgets(c->DT_catd, 1, 736, printErrorTitle));
1381
1382     report_error(c, title, text);
1383
1384     XtFree(text);
1385     XtFree(title);
1386     return;
1387   }
1388
1389   if (pd == (_DtCmPrintData *)NULL)
1390     return;
1391
1392   if (!pd->setupDataValid)
1393   {
1394     if (DtPrintFillSetupData(pd->pdb, &pd->setupData) != DtPRINT_SUCCESS)
1395     {
1396       /*
1397        * NOTE: DtPrintFillSetupData() displays an error dialog if
1398        * it is unsuccessful; no need to display our own.
1399        */
1400       return;
1401     }
1402
1403     pd->setupDataValid = True;
1404   }
1405
1406   if (XtIsManaged(pd->pdb))
1407     _DtTurnOnHourGlass(XtParent(pd->pdb));
1408
1409   createPrintShell(c);
1410
1411   switch(r)
1412   {
1413   case PR_YEAR_VIEW:
1414     print_std_year_range(year(start_date), year(end_date));
1415     break;
1416   default:
1417   case PR_MONTH_VIEW:
1418     print_month_range(c, start_date, end_date);
1419     break;
1420   case PR_WEEK_VIEW:
1421     print_week_range(c, start_date, end_date);
1422     break;
1423   case PR_DAY_VIEW:
1424     print_day_range(c, start_date, end_date);
1425     break;
1426   case PR_APPT_LIST:
1427     x_print_list_range(c, CSA_TYPE_EVENT, (int) c->view->glance,
1428                        start_date, end_date);
1429     break;
1430   case PR_TODO_LIST:
1431     x_print_list_range(c, CSA_TYPE_TODO, (int) VIEW_ALL,
1432                        start_date, end_date);
1433     break;
1434   }
1435
1436 #ifdef GR_DEBUG
1437   if (inDebugMode(c))
1438   {
1439     XtDestroyWidget(pd->printShell);
1440     pd->printShell = (Widget)NULL;
1441   }
1442 #endif
1443
1444   if (XtIsManaged(pd->pdb))
1445   {
1446     _DtTurnOffHourGlass(XtParent(pd->pdb));
1447     XtUnmanageChild(pd->pdb);
1448   }
1449
1450   /* Keep setupDataValid=True for future QuickPrint operations. */
1451 }
1452
1453 /*
1454  * report_option_cb
1455  *
1456  * callback for report-type option menu.
1457  * Here we just store the button number of the selected
1458  * button in the print_data structure, to make life easy
1459  * when the print callback is invoked.
1460  */
1461 static void
1462 report_option_cb(Widget w, XtPointer client_data, XtPointer call_data)
1463 {
1464   int choice = (int) client_data;
1465   Calendar *c = calendar;
1466
1467   pd_set_report_managed(c, choice);
1468
1469   pd_set_start_date(c, pd_get_start_date(c));
1470   pd_set_end_date(c, pd_get_end_date(c));
1471 }
1472
1473 char *
1474 pd_get_printer_name(Calendar *c)
1475 {
1476   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1477
1478   if ((pd == (_DtCmPrintData *)NULL) ||
1479       (!pd->setupDataValid) ||
1480       pd_print_to_file(c))
1481     return (char *)NULL;
1482
1483   return pd->setupData.printer_name ?
1484     XtNewString(pd->setupData.printer_name) : (char *)NULL;
1485 }
1486
1487 int
1488 pd_get_copies(Calendar *c)
1489 {
1490   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1491   int nCopies = 0;
1492
1493   if (pd == (_DtCmPrintData *)NULL)
1494     return 0;
1495
1496   XtVaGetValues(pd->pdb, DtNcopies, &nCopies, NULL);
1497   return nCopies;
1498 }
1499
1500 Tick
1501 pd_get_start_date(Calendar *c)
1502 {
1503   int dayPos, monthPos, yearPos;
1504
1505   if (!pd_get_start_positions(c, &monthPos, &dayPos, &yearPos))
1506     return 0;
1507
1508   return monthdayyear(monthPos + 1, dayPos, yearPos);
1509 }
1510
1511 Tick
1512 pd_get_end_date(Calendar *c)
1513 {
1514   int dayPos, monthPos, yearPos;
1515
1516   if (!pd_get_end_positions(c, &monthPos, &dayPos, &yearPos))
1517     return 0;
1518
1519   return monthdayyear(monthPos + 1, dayPos, yearPos);
1520 }
1521
1522 char *
1523 pd_get_print_options(Calendar *c)
1524 {
1525   return XtNewString("");
1526 }
1527
1528 Boolean
1529 pd_print_to_file(Calendar *c)
1530 {
1531   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1532
1533   if ((pd == (_DtCmPrintData *)NULL) ||
1534       (!pd->setupDataValid))
1535     return False;
1536
1537   return pd->setupData.destination == DtPRINT_TO_FILE;
1538 }
1539
1540 char *
1541 pd_get_file_name(Calendar *c)
1542 {
1543   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1544
1545   if ((pd == (_DtCmPrintData *)NULL) ||
1546       (!pd->setupDataValid) ||
1547       !pd_print_to_file(c))
1548     return (char *)NULL;
1549
1550   return pd->setupData.dest_info ?
1551     XtNewString(pd->setupData.dest_info) : (char *)NULL;
1552 }
1553
1554 int
1555 pd_get_report_type(Calendar *c)
1556 {
1557   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1558
1559   if (pd == (_DtCmPrintData *)NULL)
1560     return PR_MONTH_VIEW;
1561
1562   return pd->report_type;
1563 }
1564
1565 Widget
1566 pd_get_print_shell(Calendar *c)
1567 {
1568   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1569
1570   if (pd == (_DtCmPrintData *)NULL)
1571     return (Widget)NULL;
1572
1573   return pd->printShell;
1574 }
1575
1576 Display *
1577 pd_get_print_display(Calendar *c)
1578 {
1579   Widget printShell = pd_get_print_shell(c);
1580
1581   if (printShell == (Widget)NULL)
1582       return (Display *)NULL;
1583
1584   return XtDisplay(printShell);
1585 }
1586
1587 void
1588 pd_set_bad_alloc_error(Calendar *c, Boolean errorOn)
1589 {
1590   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1591
1592   if (pd != (_DtCmPrintData *)NULL)
1593       pd->badAllocError = errorOn;
1594 }
1595
1596 Boolean
1597 pd_get_bad_alloc_error(Calendar *c)
1598 {
1599   _DtCmPrintData *pd = (_DtCmPrintData *)c->print_data;
1600
1601   if (pd != (_DtCmPrintData *)NULL)
1602       return pd->badAllocError;
1603 }