/* Evolution calendar - Print support * * Copyright (C) 2000 Helix Code, Inc. * * Authors: Michael Zucchi * Federico Mena-Quintero * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "calendar-commands.h" #include "gnome-cal.h" #include "print.h" /* copied from gnome-month-item.c this should be shared?? */ /* Number of days in a month, for normal and leap years */ static const int days_in_month[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; /* The weird month of September 1752, where 3 Sep through 13 Sep were eliminated due to the * Gregorian reformation. */ static const int sept_1752[42] = { 0, 0, 1, 2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define REFORMATION_DAY 639787 /* First day of the reformation, counted from 1 Jan 1 */ #define MISSING_DAYS 11 /* They corrected out 11 days */ #define THURSDAY 4 /* First day of reformation */ #define SATURDAY 6 /* Offset value; 1 Jan 1 was a Saturday */ #define SEPT_1752_START 2 /* Start day within month */ #define SEPT_1752_END 20 /* End day within month */ /* FIXME: This needs to be able to render using all the options from the new * calendar configuration stuff. */ #define WEEK_STARTS_ON_MONDAY FALSE struct pdinfo { GList *slots; }; struct psinfo { GList *events; }; struct ptinfo { GList *todos; }; struct einfo { char *text; time_t start; time_t end; int count; }; /* Returns the number of leap years since year 1 up to (but not including) the specified year */ static int leap_years_up_to (int year) { return (year / 4 /* trivial leapness */ - ((year > 1700) ? (year / 100 - 17) : 0) /* minus centuries since 1700 */ + ((year > 1600) ? ((year - 1600) / 400) : 0)); /* plus centuries since 1700 divisible by 400 */ } /* Returns whether the specified year is a leap year */ static int is_leap_year (int year) { if (year <= 1752) return !(year % 4); else return (!(year % 4) && (year % 100)) || !(year % 400); } /* Returns the 1-based day number within the year of the specified date */ static int day_in_year (int day, int month, int year) { int is_leap, i; is_leap = is_leap_year (year); for (i = 0; i < month; i++) day += days_in_month [is_leap][i]; return day; } /* Returns the day of the week (zero-based, zero is Sunday) for the specified date. For the days * that were removed on the Gregorian reformation, it returns Thursday. */ static int day_in_week (int day, int month, int year) { int n; n = (year - 1) * 365 + leap_years_up_to (year - 1) + day_in_year (day, month, year); if (n < REFORMATION_DAY) return (n - 1 + SATURDAY) % 7; if (n >= (REFORMATION_DAY + MISSING_DAYS)) return (n - 1 + SATURDAY - MISSING_DAYS) % 7; return THURSDAY; } /* Fills the 42-element days array with the day numbers for the specified month. Slots outside the * bounds of the month are filled with zeros. The starting and ending indexes of the days are * returned in the start and end arguments. */ static void build_month (int month, int year, int start_on_monday, int *days, int *start, int *end) { int i; int d_month, d_week; /* Note that months are zero-based, so September is month 8 */ if ((year == 1752) && (month == 8)) { memcpy (days, sept_1752, 42 * sizeof (int)); if (start) *start = SEPT_1752_START; if (end) *end = SEPT_1752_END; return; } for (i = 0; i < 42; i++) days[i] = 0; d_month = days_in_month[is_leap_year (year)][month]; d_week = day_in_week (1, month, year); if (start_on_monday) d_week = (d_week + 6) % 7; for (i = 0; i < d_month; i++) days[d_week + i] = i + 1; if (start) *start = d_week; if (end) *end = d_week + d_month - 1; } enum align_box { ALIGN_LEFT=1, ALIGN_RIGHT, ALIGN_CENTRE, ALIGN_BORDER= 1<<8 }; /* width = width of border, -'ve is no border fillcolour = shade of fill, -'ve is no fill */ static void print_border(GnomePrintContext *pc, double l, double r, double t, double b, double width, double fillcolour) { int i; gnome_print_gsave (pc); if (fillcolour<0.0) i=1; else i=0; for (;i<2;i++) { gnome_print_moveto(pc, l, t); gnome_print_lineto(pc, l, b); gnome_print_lineto(pc, r, b); gnome_print_lineto(pc, r, t); gnome_print_lineto(pc, l, t); if (i==0) { gnome_print_setrgbcolor(pc, fillcolour, fillcolour, fillcolour); gnome_print_fill(pc); if (width<0.0) i=2; } else { gnome_print_setrgbcolor(pc, 0, 0, 0); gnome_print_setlinewidth(pc, width); gnome_print_stroke(pc); } } gnome_print_grestore (pc); } /* outputs 1 line of aligned text in a box */ static void print_text(GnomePrintContext *pc, GnomeFont *font, const char *text, enum align_box align, double l, double r, double t, double b) { double w, x; gnome_print_gsave (pc); w = gnome_font_get_width_string(font, text); switch (align&3) { default: case ALIGN_LEFT: x = l; break; case ALIGN_RIGHT: x = l+(r-l)-w-2; break; case ALIGN_CENTRE: x = l+((r-l)-w)/2; break; } gnome_print_moveto(pc, x, t - gnome_font_get_size (font)); gnome_print_setfont(pc, font); gnome_print_setrgbcolor (pc, 0,0,0); gnome_print_show(pc, text); gnome_print_grestore (pc); } /* gets/frees the font for you, as a bold font */ static void print_text_size(GnomePrintContext *pc, double size, const char *text, enum align_box align, double l, double r, double t, double b) { GnomeFont *font; font = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, size); print_text(pc, font, text, align, l, r, t, b); gtk_object_unref (GTK_OBJECT (font)); } static void titled_box(GnomePrintContext *pc, const char *text, GnomeFont *font, enum align_box align, double *l, double *r, double *t, double *b, double linewidth) { if (align&ALIGN_BORDER) { gnome_print_gsave(pc); print_border(pc, *l, *r, *t, *t-gnome_font_get_size(font)-gnome_font_get_size(font)*0.4, linewidth, 0.9); print_border(pc, *l, *r, *t-gnome_font_get_size(font)-gnome_font_get_size(font)*0.4, *b, linewidth, -1.0); gnome_print_grestore(pc); *l+=2; *r-=2; *b+=2; } print_text(pc, font, text, align, *l, *r, *t, *b); *t-=gnome_font_get_size(font)*1.4; } enum datefmt { DATE_MONTH = 1 << 0, DATE_DAY = 1 << 1, DATE_DAYNAME = 1 << 2, DATE_YEAR = 1 << 3 }; static char *days[] = { N_("1st"), N_("2nd"), N_("3rd"), N_("4th"), N_("5th"), N_("6th"), N_("7th"), N_("8th"), N_("9th"), N_("10th"), N_("11th"), N_("12th"), N_("13th"), N_("14th"), N_("15th"), N_("16th"), N_("17th"), N_("18th"), N_("19th"), N_("20th"), N_("21st"), N_("22nd"), N_("23rd"), N_("24th"), N_("25th"), N_("26th"), N_("27th"), N_("28th"), N_("29th"), N_("30th"), N_("31st") }; /* format the date 'nicely' and consistently for various headers */ static char * format_date(time_t time, int flags, char *buffer, int bufflen) { char fmt[64]; struct tm tm; tm = *localtime(&time); fmt[0] = 0; if (flags & DATE_DAYNAME) { strcat(fmt, "%A"); } if (flags & DATE_DAY) { if (flags & DATE_DAYNAME) strcat(fmt, " "); strcat(fmt, gettext(days[tm.tm_mday-1])); } if (flags & DATE_MONTH) { if (flags & (DATE_DAY|DATE_DAYNAME)) strcat(fmt, " "); strcat(fmt, "%B"); if ((flags & (DATE_DAY|DATE_YEAR)) == (DATE_DAY|DATE_YEAR)) strcat(fmt, ","); } if (flags & DATE_YEAR) { if (flags & (DATE_DAY|DATE_DAYNAME|DATE_MONTH)) strcat(fmt, " "); strcat(fmt, "%Y"); } strftime(buffer, bufflen, fmt, &tm); return buffer; } /* print out the month small, embolden any days with events. */ static void print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, double left, double right, double top, double bottom, int titleflags, time_t greystart, time_t greyend, int bordertitle) { CalClient *client; GnomeFont *font, *font_bold, *font_normal; time_t now, next; int x, y; int days[42]; int day; char buf[100]; struct tm tm; double xpad, ypad, size; char *daynames[] = { _("Su"), _("Mo"), _("Tu"), _("We"), _("Th"), _("Fr"), _("Sa") }; client = gnome_calendar_get_cal_client (gcal); xpad = (right-left)/7; ypad = (top-bottom)/8.3; if (xpad>ypad) size=ypad; else size=xpad; size = (xpad+ypad)/3.0; tm = *localtime (&month); /* get month days */ build_month(tm.tm_mon, tm.tm_year+1900, WEEK_STARTS_ON_MONDAY, days, 0, 0); /* build day-busy bits */ now = time_month_begin(month); /* get title */ format_date(month, titleflags, buf, 100); font = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 1, size*1.2); /* title font */ if (bordertitle) print_border(pc, left, left+7*xpad, top, top-gnome_font_get_size(font)*1.3, 1.0, 0.9); print_text(pc, font, buf, ALIGN_CENTRE, left, left+7*xpad, top, top - gnome_font_get_size (font)); gtk_object_unref (GTK_OBJECT (font)); font_normal = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, size); font_bold = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, size); gnome_print_setrgbcolor (pc, 0,0,0); for (x=0;x<7;x++) { print_text(pc, font_bold, daynames[(WEEK_STARTS_ON_MONDAY?x+1:x)%7], ALIGN_CENTRE, left+x*xpad, left+(x+1)*xpad, bottom+7*ypad, bottom+7*ypad-gnome_font_get_size(font_bold)); } for (y=0;y<6;y++) { for (x=0;x<7;x++) { day = days[y*7+x]; if (day!=0) { GList *uids; sprintf(buf, "%d", day); /* this is a slow messy way to do this ... but easy ... */ uids = cal_client_get_objects_in_range (client, CALOBJ_TYPE_EVENT, now, time_day_end (now)); font = uids ? font_bold : font_normal; cal_obj_uid_list_free (uids); next = time_add_day(now, 1); if ((now>=greystart && now=now && greystart=outbuffendmarker) { char *newbuf; outbufflen*=2; newbuf = g_realloc(outbuffer, outbufflen); o = newbuf+(o-outbuffer); wordstart = newbuf+(o-outbuffer); outbuffer = newbuf; outbuffendmarker = outbuffer+outbufflen-2; } *o++=c; if (c==' ') wordstart = o; width+=gnome_font_get_glyph_width(font, gnome_font_lookup_default (font, c)); if (width>maxwidth) dump=1; else dump=0; } if (dump) { if (wordstart==outbuffer) wordstart=o; c=*wordstart; *wordstart=0; gnome_print_moveto(pc, left, top); gnome_print_show(pc, outbuffer); *wordstart=c; memcpy(outbuffer, wordstart, o-wordstart); width = gnome_font_get_width_string_n(font, outbuffer, o-wordstart); o=outbuffer+(o-wordstart); wordstart = outbuffer; top -= gnome_font_get_size (font); if (toptext = g_strdup (text.value); ei->start = istart; ei->end = iend; ei->count = 0; for (l = pdi->slots; l; l = l->next) { struct einfo *testei; col = (GList *)l->data; testei = (struct einfo *)col->data; if (ei->start >= testei->end) { col = g_list_prepend (col, ei); l->data = col; return TRUE; } testei->count++; ei->count++; } col = NULL; col = g_list_prepend (col, ei); pdi->slots = g_list_append (pdi->slots, col); return TRUE; } static void print_day_details (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom) { CalClient *client; struct pdinfo pdi; time_t start, end; GList *l; int num_slots, i; GnomeFont *font_hour, *font_minute, *font_summary; double yinc, y, yend, x, xend; double width=40, slot_width; char buf[20]; client = gnome_calendar_get_cal_client (gcal); yinc = (top-bottom)/24; /* fill static detail */ font_hour = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, yinc/2); font_minute = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, yinc/3); font_summary = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, yinc/3); gnome_print_setrgbcolor (pc, 0, 0, 0); /* internal lines */ gnome_print_setlinewidth(pc, 0.0); gnome_print_moveto(pc, left+width, bottom); gnome_print_lineto(pc, left+width, top); gnome_print_stroke (pc); for (i=0;i<24;i++) { y = top - yinc*(i+1); print_border(pc, left+1, left+width-1, y, y+yinc-1, -1.0, 0.9); gnome_print_setrgbcolor (pc, 0, 0, 0); /* the hour label/minute */ sprintf(buf, "%d", i); print_text(pc, font_hour, buf, ALIGN_RIGHT, left, left+width/2, y+yinc, y); switch(i) { case 12: sprintf(buf, _("pm")); break; case 0: sprintf(buf, _("am")); break; default: sprintf(buf, "00"); break; } print_text(pc, font_minute, buf, ALIGN_LEFT, left+width/2, left+width/2, y+yinc, y); /* internal lines */ gnome_print_moveto(pc, left+width, y); gnome_print_lineto(pc, right, y); gnome_print_stroke (pc); gnome_print_moveto(pc, left+width/2, y+yinc/2); gnome_print_lineto(pc, right, y+yinc/2); gnome_print_stroke (pc); } start = time_day_begin(whence); end = time_day_end(start); pdi.slots = NULL; cal_client_generate_instances (client, CALOBJ_TYPE_EVENT, start, end, print_day_details_cb, &pdi); num_slots = g_list_length (pdi.slots); slot_width = (right-left-width)/num_slots; for (i = num_slots, l = pdi.slots; l; i--, l = l->next) { GList *e = (GList *)l->data; for (; e; e = e->next) { struct einfo *ei = (struct einfo *)e->data; y = top - (top - bottom) * (ei->start - start) / (end - start) - 1; yend = top - (top - bottom) * (ei->end - start) / (end - start) + 1; x = left + width + slot_width * (num_slots - i); if (num_slots > 0) x++; if (i == 0) xend = x + (num_slots - ei->count) * slot_width - 2; else xend = x + slot_width - 2; print_border (pc, x, xend, y, yend, 0.0, 0.9); bound_text (pc, font_summary, ei->text, x, xend, y, yend, 0); g_free (ei); } g_list_free (e); } g_list_free (pdi.slots); print_border (pc, left, right, top, bottom, 1.0, -1.0); gtk_object_unref (GTK_OBJECT (font_hour)); gtk_object_unref (GTK_OBJECT (font_minute)); gtk_object_unref (GTK_OBJECT (font_summary)); } /* * Print Day Summary */ #if 0 #define TIME_FMT "%X" #else #define TIME_FMT "%l:%M%p" #endif static gboolean print_day_summary_cb (CalComponent *comp, time_t istart, time_t iend, gpointer data) { CalComponentText text; struct psinfo *psi = (struct psinfo *)data; struct einfo *ei; ei = g_new (struct einfo, 1); cal_component_get_summary (comp, &text); ei->text = g_strdup (text.value); ei->start = istart; ei->end = iend; ei->count = 0; psi->events = g_list_append (psi->events, ei); return TRUE; } static void print_day_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom, double size, int totime, int titleformat) { CalClient *client; struct psinfo psi; time_t start, end; GList *l; GnomeFont *font_summary; double y, yend, x, xend, inc, incsmall; char buf[100]; double margin; struct tm tm; client = gnome_calendar_get_cal_client (gcal); /* fill static detail */ font_summary = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, size); gnome_print_setfont (pc, font_summary); start = time_day_begin(whence); end = time_day_end(start); tm = *localtime(&start); format_date(start, titleformat, buf, 100); titled_box (pc, buf, font_summary, ALIGN_RIGHT | ALIGN_BORDER, &left, &right, &top, &bottom, 0.0); psi.events = NULL; cal_client_generate_instances (client, CALOBJ_TYPE_EVENT, start, end, print_day_summary_cb, &psi); inc = size*0.3; incsmall = size*0.2; y = top-inc; yend = bottom-incsmall; /* do a good rough approximation of the 'widest' time */ tm.tm_year = 2000; tm.tm_mon = 12; tm.tm_mday = 22; tm.tm_sec = 22; tm.tm_min = 22; tm.tm_hour = 23; strftime(buf, 100, TIME_FMT, &tm); margin = gnome_font_get_width_string(font_summary, buf); for (l = psi.events; l; l = l->next) { struct einfo *ei = (struct einfo *)l->data; x = left + incsmall; xend = right - inc; if (y - gnome_font_get_size (font_summary) < bottom) break; tm = *localtime (&ei->start); strftime (buf, 100, TIME_FMT, &tm); gnome_print_moveto (pc, x + (margin - gnome_font_get_width_string (font_summary, buf)), y - gnome_font_get_size (font_summary)); gnome_print_show (pc, buf); if (totime) { tm = *localtime (&ei->end); strftime (buf, 100, TIME_FMT, &tm); gnome_print_moveto (pc, (x + margin + inc + (margin - gnome_font_get_width_string (font_summary, buf))), y - gnome_font_get_size (font_summary)); gnome_print_show (pc, buf); y = bound_text (pc, font_summary, ei->text, x + margin * 2 + inc * 2, xend, y, yend, 0); } else { /* we also indent back after each time is printed */ y = bound_text (pc, font_summary, ei->text, x + margin + inc, xend, y, yend, -margin + inc); } y += gnome_font_get_size (font_summary) - inc; g_free (ei); } g_list_free (psi.events); gtk_object_unref (GTK_OBJECT (font_summary)); } static void print_week_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom) { double y, l, r, t, b; time_t now; int i; l = left; r = (right-left)/2+left; t = top; y = (top-bottom)/3; b = top-y; now = time_week_begin(whence); /* returns sunday, we need monday */ now = time_add_day(now, 1); for (i = 0; i < 7; i++) { print_day_summary (pc, gcal, now, l, r, t, b, 10, TRUE, DATE_DAY | DATE_DAYNAME | DATE_MONTH); now = time_add_day (now, 1); switch (i) { case 5: y /= 2.0; b += y; case 0: case 1: case 3: case 4: t -= y; b -= y; break; case 2: l = r; r = right; t = top; b = t-y; break; case 6: break; } } } static void print_year_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom, int morerows) { double y, x, l, r, t, b; time_t now; int xx, yy, rows, cols; l = left; t = top; if (morerows) { rows=4; cols=3; } else { rows=3; cols=4; } y = (top-bottom)/rows; x = (right-left)/cols; r = l+x; b = top-y; now = time_year_begin(whence); for (yy = 0; yy < rows; yy++) { t = top - y * yy; b = t - y; for (xx = 0; xx < cols; xx++) { l = left + x * xx; r = l + x; print_month_small (pc, gcal, now, l + 8, r - 8, t - 8, b + 8, DATE_MONTH, 0, 0, TRUE); now = time_add_month (now, 1); } } } static void print_month_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom) { time_t now, today; int days[42]; int day; struct tm tm; int x, y; char buf[100]; GnomeFont *font_days; now = time_month_begin(whence); tm = *localtime (&now); /* get month days */ build_month(tm.tm_mon, tm.tm_year+1900, WEEK_STARTS_ON_MONDAY, days, 0, 0); /* a little margin */ top -= 4; /* do day names ... */ font_days = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, 10); gnome_print_setfont(pc, font_days); for (x=0;x<7;x++) { today = time_add_day(now, days[6+x]); format_date(today, DATE_DAYNAME, buf, 100); print_text(pc, font_days, buf, ALIGN_CENTRE, (right-left)*x/7+left, (right-left)*(x+1)/7+left, top, top-gnome_font_get_size(font_days)); } top -= gnome_font_get_size(font_days)*1.5; gtk_object_unref (GTK_OBJECT (font_days)); for (y=0;y<6;y++) { for (x=0;x<7;x++) { day = days[y*7+x]; if (day!=0) { print_day_summary (pc, gcal, now, (right-left)*x/7+left, (right-left)*(x+1)/7+left, top - (top-bottom)*y/6, top - (top-bottom)*(y+1)/6, 6, FALSE, day==1?(DATE_DAY|DATE_MONTH):DATE_DAY); now = time_add_day(now, 1); } } } } static void print_todo_details (GnomePrintContext *pc, GnomeCalendar *gcal, time_t start, time_t end, double left, double right, double top, double bottom) { CalClient *client; GList *uids; GList *l; GnomeFont *font_summary; double y, yend, x, xend; client = gnome_calendar_get_cal_client (gcal); font_summary = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, 10); gnome_print_setrgbcolor (pc, 0, 0, 0); gnome_print_setlinewidth (pc, 0.0); titled_box (pc, _("Tasks"), font_summary, ALIGN_CENTRE | ALIGN_BORDER, &left, &right, &top, &bottom, 1.0); y = top - 3; yend = bottom - 2; uids = cal_client_get_uids (client, CALOBJ_TYPE_TODO); for (l = uids; l; l = l->next) { char *uid; CalComponent *comp; CalClientGetStatus status; CalComponentText summary; uid = l->data; status = cal_client_get_object (client, uid, &comp); switch (status) { case CAL_CLIENT_GET_SUCCESS: break; case CAL_CLIENT_GET_NOT_FOUND: /* Nothing: the object may have been removed from the server */ continue; case CAL_CLIENT_GET_SYNTAX_ERROR: g_message ("print_todo_details(): Syntax error while getting object `%s'", uid); continue; default: g_assert_not_reached (); } cal_component_get_summary (comp, &summary); if (!summary.value) continue; x = left; xend = right - 2; if (y < bottom) break; y = bound_text (pc, font_summary, summary.value, x + 2, xend, y, yend, 0); y += gnome_font_get_size (font_summary); gnome_print_moveto (pc, x, y - 3); gnome_print_lineto (pc, xend, y - 3); gnome_print_stroke (pc); y -= 3; } cal_obj_uid_list_free (uids); gtk_object_unref (GTK_OBJECT (font_summary)); } #if 0 static GnomePrintContext * print_context (int preview, char *paper) { GtkWidget *toplevel, *canvas, *sw; GnomePrinter *printer; GnomePrintContext *pc; if (preview) { gtk_widget_push_colormap (gdk_rgb_get_cmap ()); gtk_widget_push_visual (gdk_rgb_get_visual ()); toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize (toplevel, 700, 700); sw = gtk_scrolled_window_new (NULL, NULL); canvas = gnome_canvas_new_aa (); gtk_container_add (GTK_CONTAINER (toplevel), sw); gtk_container_add (GTK_CONTAINER (sw), canvas); gnome_canvas_set_pixels_per_unit((GnomeCanvas *)canvas, 1); pc = gnome_print_preview_new ((GnomeCanvas *)canvas, paper); gtk_widget_show_all (toplevel); gtk_widget_pop_visual (); gtk_widget_pop_colormap (); } else { printer = gnome_printer_dialog_new_modal (); if (!printer) return NULL; pc = gnome_print_context_new_with_paper_size (printer, paper); } return pc; } #endif /* Value for the PrintView enum */ static const int print_view_map[] = { PRINT_VIEW_DAY, PRINT_VIEW_WEEK, PRINT_VIEW_MONTH, PRINT_VIEW_YEAR, -1 }; /* Creates the range selector widget for printing a calendar */ static GtkWidget * range_selector_new (GtkWidget *dialog, time_t at, int *view) { GtkWidget *box; GtkWidget *radio; GSList *group; char text[1024]; char str1[512]; char str2[512]; struct tm tm; time_t week_begin, week_end; struct tm week_begin_tm, week_end_tm; box = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); tm = *localtime (&at); /* Day */ strftime (text, sizeof (text), _("Current day (%a %b %d %Y)"), &tm); radio = gtk_radio_button_new_with_label (NULL, text); group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0); /* Week */ week_begin = time_week_begin (at); week_end = time_add_day (time_week_end (at), -1); week_begin_tm = *localtime (&week_begin); week_end_tm = *localtime (&week_end); if (week_begin_tm.tm_mon == week_end_tm.tm_mon) { strftime (str1, sizeof (str1), _("%a %b %d"), &week_begin_tm); strftime (str2, sizeof (str2), _("%a %d %Y"), &week_end_tm); } else { if (week_begin_tm.tm_year == week_end_tm.tm_year) { strftime (str1, sizeof (str1), _("%a %b %d"), &week_begin_tm); strftime (str2, sizeof (str2), _("%a %b %d %Y"), &week_end_tm); } else { strftime (str1, sizeof (str1), _("%a %b %d %Y"), &week_begin_tm); strftime (str2, sizeof (str2), _("%a %b %d %Y"), &week_end_tm); } } g_snprintf (text, sizeof (text), _("Current week (%s - %s)"), str1, str2); radio = gtk_radio_button_new_with_label (group, text); group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0); /* Month */ strftime (text, sizeof (text), _("Current month (%b %Y)"), &tm); radio = gtk_radio_button_new_with_label (group, text); group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0); /* Year */ strftime (text, sizeof (text), _("Current year (%Y)"), &tm); radio = gtk_radio_button_new_with_label (group, text); group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0); /* Select default */ e_dialog_widget_hook_value (dialog, radio, view, (gpointer) print_view_map); gtk_widget_show_all (box); return box; } void print_calendar (GnomeCalendar *gcal, gboolean preview, time_t at, PrintView default_view) { GnomePrinter *printer; GnomePrintMaster *gpm; GnomePrintContext *pc; int copies, collate; const GnomePaper *paper_info; double l, r, t, b, todo, header; char buf[100]; time_t when; g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); printer = NULL; copies = 1; collate = FALSE; if (!preview) { GtkWidget *gpd; GtkWidget *range; int view; gpd = gnome_print_dialog_new (_("Print Calendar"), GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES); view = (int) default_view; range = range_selector_new (gpd, at, &view); gnome_print_dialog_construct_range_custom (GNOME_PRINT_DIALOG (gpd), range); gnome_dialog_set_default (GNOME_DIALOG (gpd), GNOME_PRINT_PRINT); /* Run dialog */ switch (gnome_dialog_run (GNOME_DIALOG (gpd))) { case GNOME_PRINT_PRINT: break; case GNOME_PRINT_PREVIEW: preview = TRUE; break; case -1: return; default: gnome_dialog_close (GNOME_DIALOG (gpd)); return; } e_dialog_get_values (gpd); default_view = (PrintView) view; gnome_print_dialog_get_copies (GNOME_PRINT_DIALOG (gpd), &copies, &collate); printer = gnome_print_dialog_get_printer (GNOME_PRINT_DIALOG (gpd)); gnome_dialog_close (GNOME_DIALOG (gpd)); } /* FIXME: allow configuration of paper size */ gpm = gnome_print_master_new (); paper_info = gnome_paper_with_name (gnome_paper_name_default ()); gnome_print_master_set_paper (gpm, paper_info); if (printer) gnome_print_master_set_printer (gpm, printer); gnome_print_master_set_copies (gpm, copies, collate); pc = gnome_print_master_get_context (gpm); l = gnome_paper_lmargin (paper_info); r = gnome_paper_pswidth (paper_info) - gnome_paper_rmargin (paper_info); t = gnome_paper_psheight (paper_info) - gnome_paper_tmargin (paper_info); b = gnome_paper_bmargin (paper_info); /* depending on the view, do a different output */ switch (default_view) { case PRINT_VIEW_DAY: { int i, days = 1; for (i = 0; i < days; i++) { todo = ((r - l) / 5) * 4 + l; header = t - 70; print_todo_details (pc, gcal, 0, INT_MAX, todo, r, header, b); print_day_details (pc, gcal, at, l, todo - 2.0, header, b); print_border (pc, l, r, t, header + 2.0, 1.0, 0.9); print_month_small (pc, gcal, at, r - 190, r - 104, t - 4, header + 8, DATE_MONTH | DATE_YEAR, at, at, FALSE); print_month_small (pc, gcal, time_add_month (at, 1), r - 90, r - 4, t - 4, header + 8, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); format_date (at, DATE_DAY | DATE_MONTH | DATE_YEAR, buf, 100); print_text_size (pc, 24, buf, ALIGN_LEFT, l + 3, todo, t - 3, header); format_date (at, DATE_DAYNAME, buf, 100); print_text_size (pc, 18, buf, ALIGN_LEFT, l + 3, todo, t - 27 - 4, header); gnome_print_showpage (pc); at = time_add_day (at, 1); } break; } case PRINT_VIEW_WEEK: header = t - 70; print_week_summary (pc, gcal, at, l, r, header, b); /* more solid total outline */ print_border (pc, l, r, header, b, 1.0, -1.0); /* header border */ print_border (pc, l, r, t, header + 2.0, 1.0, 0.9); when = time_week_begin (at); when = time_add_day (when, 1); print_month_small (pc, gcal, at, r - 90, r - 4, t - 4, header + 8, DATE_MONTH | DATE_YEAR, when, time_add_week (when, 1), FALSE); print_month_small (pc, gcal, time_add_month (at, -1), r - 190, r - 104, t - 4, header + 8, DATE_MONTH | DATE_YEAR, when, time_add_week (when, 1), FALSE); format_date (when, DATE_DAY | DATE_MONTH | DATE_YEAR, buf, 100); print_text_size (pc, 24, buf, ALIGN_LEFT, l + 3, r, t - 4, header); when = time_add_day (when, 6); format_date (when, DATE_DAY | DATE_MONTH | DATE_YEAR, buf, 100); print_text_size (pc, 24, buf, ALIGN_LEFT, l + 3, r, t - 24 - 3, header); gnome_print_showpage (pc); break; case PRINT_VIEW_MONTH: header = t - 70; gnome_print_rotate (pc, 90); gnome_print_translate (pc, 0, -gnome_paper_pswidth (paper_info)); /*print_month_summary(pc, cal, at, l, r, header, b);*/ print_month_summary (pc, gcal, at, b, t, r - 70, l); print_border (pc, b, t, r, r - 72.0, 1.0, 0.9); print_month_small (pc, gcal, time_add_month (at, 1), t - (t - b) / 7 + 2, t - 8, r - 4, r - 68, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); print_month_small (pc, gcal, time_add_month (at, -1), b + 8, b + (t - b) / 7 - 2, r - 4, r - 68, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); /* centered title */ format_date (at, DATE_MONTH | DATE_YEAR, buf, 100); print_text_size (pc, 24, buf, ALIGN_CENTRE, b + 3, t, r - 3, l); gnome_print_showpage (pc); break; case PRINT_VIEW_YEAR: #if 0 /* landscape */ gnome_print_rotate(pc, 90); gnome_print_translate(pc, 0, -gnome_paper_pswidth(paper_info)); print_year_summary(pc, gcal, at, b, t, r-50, l, FALSE); /* centered title */ format_date(at, DATE_YEAR, buf, 100); print_text_size(pc, 24, buf, ALIGN_CENTRE, b+3, t, r-3, l); #else /* portrait */ print_year_summary(pc, gcal, at, l, r, t-50, b, TRUE); /* centered title */ format_date(at, DATE_YEAR, buf, 100); print_text_size(pc, 24, buf, ALIGN_CENTRE, l+3, r, t-3, b); #endif gnome_print_showpage(pc); break; default: g_assert_not_reached (); } gnome_print_master_close (gpm); if (preview) { GnomePrintMasterPreview *gpmp; gpmp = gnome_print_master_preview_new (gpm, _("Print Preview")); gtk_widget_show (GTK_WIDGET (gpmp)); } else gnome_print_master_print (gpm); gtk_object_unref (GTK_OBJECT (gpm)); }