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