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