From 21e41f438e4761587b0ea42db80b23dde1eb59e3 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Fri, 28 Aug 1998 00:29:59 +0000 Subject: Today: fixed calculation of day indexes when weeks start on Monday. The Today: fixed calculation of day indexes when weeks start on Monday. The year view now marks days (and fixed bugs in day marking as well). Next step: make a generic month-marker routine and use that all over the place. 1998-08-27 Federico Mena Quintero * gnome-month-item.c (build_month): Now does the correct thing when the user wants weeks to start on Monday. Now all the Monday special casing, as far as day numbering is concerned, is only in this function. * year-view.c (mark_days): This function marks the days that have events in them. It also fixes a memory leak in the old implementation (it was leaking the whole list). (unmark_days): New function used to unmark all the days in the year view. (mark_event): New function that marks all the days that are spanned by a time range. It also fixes the bug in the old implementation where it could possibly mark days past the ends of the year (if the event crosses year boundaries, for example). * timeutil.c (time_year_begin): Take the year parameter since year 1, not 1900. (time_year_end): Likewise. * year-view.c (year_view_size_allocate): Now changing the size of the calendars is done in the idle loop. (idle_handler): This function actually does the resizing of the items. * year-view.h (struct _YearView): Added idle_id and need_resize fields. svn path=/trunk/; revision=346 --- calendar/ChangeLog | 28 +++ calendar/TODO | 22 +- calendar/calendar.h | 12 +- calendar/gnome-month-item.c | 16 +- calendar/gnome-month-item.h | 2 +- calendar/gui/calendar.h | 12 +- calendar/gui/gnome-month-item.c | 16 +- calendar/gui/gnome-month-item.h | 2 +- calendar/gui/year-view.c | 525 +++++++++++++++++----------------------- calendar/gui/year-view.h | 6 + calendar/timeutil.c | 4 +- calendar/year-view.c | 525 +++++++++++++++++----------------------- calendar/year-view.h | 6 + 13 files changed, 531 insertions(+), 645 deletions(-) (limited to 'calendar') diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 498ca2d484..174de9483f 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,31 @@ +1998-08-27 Federico Mena Quintero + + * gnome-month-item.c (build_month): Now does the correct thing + when the user wants weeks to start on Monday. Now all the Monday + special casing, as far as day numbering is concerned, is only in + this function. + + * year-view.c (mark_days): This function marks the days that have + events in them. It also fixes a memory leak in the old + implementation (it was leaking the whole list). + (unmark_days): New function used to unmark all the days in the + year view. + (mark_event): New function that marks all the days that are + spanned by a time range. It also fixes the bug in the old + implementation where it could possibly mark days past the ends of + the year (if the event crosses year boundaries, for example). + + * timeutil.c (time_year_begin): Take the year parameter since year + 1, not 1900. + (time_year_end): Likewise. + + * year-view.c (year_view_size_allocate): Now changing the size of + the calendars is done in the idle loop. + (idle_handler): This function actually does the resizing of the items. + + * year-view.h (struct _YearView): Added idle_id and need_resize + fields. + 1998-08-26 Federico Mena Quintero * year-view.c: Beginning of the new year view. Sizing and event diff --git a/calendar/TODO b/calendar/TODO index eca41ce244..11ce1d577a 100644 --- a/calendar/TODO +++ b/calendar/TODO @@ -1,3 +1,8 @@ +BUGS: + +- Recurrence end date is wrong. An event that repeats daily will not + be included in the ending date of the recurrence (off-by-one error?). + Month view: - Display little boxes for the appointments of each day. @@ -8,7 +13,22 @@ Month view: Year view: -- Make it use GnomeMonthItem to make it have a reasonable size. +- Use a generic mark_month() function to mark a GnomeMonthItem with + all the events that touch it. Pass a function to mark_month() that + actually does the marking (the year view and goto dialog just change + the color of the days with events; the month view does more + sophisticated layout). + +- Double click on a day takes you to the day view. + +- Button-3 popup with options: + Create new appointment in this day + --- separator --- + Go to this day + Go to this week + Go to this month + +- See why it is so fucking slow. Week view: diff --git a/calendar/calendar.h b/calendar/calendar.h index 0a0e949d92..c12ce639b7 100644 --- a/calendar/calendar.h +++ b/calendar/calendar.h @@ -48,15 +48,17 @@ gint calendar_compare_by_dtstart (gpointer a, gpointer b); void calendar_iterate_on_objects (GList *objects, time_t start, time_t end, calendarfn cb, void *closure); void calendar_iterate (Calendar *cal, time_t start, time_t end, calendarfn cb, void *closure); -/* Note this routine returns a GList with CalendarObjects */ -GList *calendar_get_events_in_range (Calendar *cal, time_t start, time_t end); +/* Returns a list of CalendarObject structures. These represent the events in the calendar that are + * in the specified range. + */ +GList *calendar_get_events_in_range (Calendar *cal, time_t start, time_t end); + +/* Destroy list returned by calendar_get_events_in_range() with this function */ +void calendar_destroy_event_list (GList *l); /* Informs the calendar that obj information has changed */ void calendar_object_changed (Calendar *cal, iCalObject *obj, int flags); -/* Destroy the above list with this method */ -void calendar_destroy_event_list (GList *l); - void calendar_notify (time_t, void *data); END_GNOME_DECLS diff --git a/calendar/gnome-month-item.c b/calendar/gnome-month-item.c index 308207f5a1..eb0c5eb469 100644 --- a/calendar/gnome-month-item.c +++ b/calendar/gnome-month-item.c @@ -407,7 +407,7 @@ day_in_week (int day, int month, int year) * returned in the start and end arguments. */ static void -build_month (int month, int year, int *days, int *start, int *end) +build_month (int month, int year, int start_on_monday, int *days, int *start, int *end) { int i; int d_month, d_week; @@ -432,6 +432,9 @@ build_month (int month, int year, int *days, int *start, int *end) 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; @@ -446,20 +449,15 @@ build_month (int month, int year, int *days, int *start, int *end) static void set_days (GnomeMonthItem *mitem) { - int i, ofs; + int i; int start, end; char buf[100]; - build_month (mitem->month, mitem->year, mitem->day_numbers, &start, &end); - - if (mitem->start_on_monday) - ofs = (start + 6) % 7; - else - ofs = start; + build_month (mitem->month, mitem->year, mitem->start_on_monday, mitem->day_numbers, &start, &end); /* Clear days before start of month */ - for (i = 0; i < ofs; i++) + for (i = 0; i < start; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "text", NULL, NULL); diff --git a/calendar/gnome-month-item.h b/calendar/gnome-month-item.h index 405fda3702..d117aa85b5 100644 --- a/calendar/gnome-month-item.h +++ b/calendar/gnome-month-item.h @@ -106,7 +106,7 @@ struct _GnomeMonthItem { GtkAnchorType day_anchor; /* Anchor side for the day number labels */ GnomeCanvasItem **items; /* All the items that make up the calendar */ - int day_numbers[42]; /* The numbers of the days */ + int day_numbers[42]; /* The numbers of the days, as they are shown in the display */ GdkFont *head_font; /* Font for the headings */ GdkFont *day_font; /* Font for the day numbers */ diff --git a/calendar/gui/calendar.h b/calendar/gui/calendar.h index 0a0e949d92..c12ce639b7 100644 --- a/calendar/gui/calendar.h +++ b/calendar/gui/calendar.h @@ -48,15 +48,17 @@ gint calendar_compare_by_dtstart (gpointer a, gpointer b); void calendar_iterate_on_objects (GList *objects, time_t start, time_t end, calendarfn cb, void *closure); void calendar_iterate (Calendar *cal, time_t start, time_t end, calendarfn cb, void *closure); -/* Note this routine returns a GList with CalendarObjects */ -GList *calendar_get_events_in_range (Calendar *cal, time_t start, time_t end); +/* Returns a list of CalendarObject structures. These represent the events in the calendar that are + * in the specified range. + */ +GList *calendar_get_events_in_range (Calendar *cal, time_t start, time_t end); + +/* Destroy list returned by calendar_get_events_in_range() with this function */ +void calendar_destroy_event_list (GList *l); /* Informs the calendar that obj information has changed */ void calendar_object_changed (Calendar *cal, iCalObject *obj, int flags); -/* Destroy the above list with this method */ -void calendar_destroy_event_list (GList *l); - void calendar_notify (time_t, void *data); END_GNOME_DECLS diff --git a/calendar/gui/gnome-month-item.c b/calendar/gui/gnome-month-item.c index 308207f5a1..eb0c5eb469 100644 --- a/calendar/gui/gnome-month-item.c +++ b/calendar/gui/gnome-month-item.c @@ -407,7 +407,7 @@ day_in_week (int day, int month, int year) * returned in the start and end arguments. */ static void -build_month (int month, int year, int *days, int *start, int *end) +build_month (int month, int year, int start_on_monday, int *days, int *start, int *end) { int i; int d_month, d_week; @@ -432,6 +432,9 @@ build_month (int month, int year, int *days, int *start, int *end) 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; @@ -446,20 +449,15 @@ build_month (int month, int year, int *days, int *start, int *end) static void set_days (GnomeMonthItem *mitem) { - int i, ofs; + int i; int start, end; char buf[100]; - build_month (mitem->month, mitem->year, mitem->day_numbers, &start, &end); - - if (mitem->start_on_monday) - ofs = (start + 6) % 7; - else - ofs = start; + build_month (mitem->month, mitem->year, mitem->start_on_monday, mitem->day_numbers, &start, &end); /* Clear days before start of month */ - for (i = 0; i < ofs; i++) + for (i = 0; i < start; i++) gnome_canvas_item_set (mitem->items[GNOME_MONTH_ITEM_DAY_LABEL + i], "text", NULL, NULL); diff --git a/calendar/gui/gnome-month-item.h b/calendar/gui/gnome-month-item.h index 405fda3702..d117aa85b5 100644 --- a/calendar/gui/gnome-month-item.h +++ b/calendar/gui/gnome-month-item.h @@ -106,7 +106,7 @@ struct _GnomeMonthItem { GtkAnchorType day_anchor; /* Anchor side for the day number labels */ GnomeCanvasItem **items; /* All the items that make up the calendar */ - int day_numbers[42]; /* The numbers of the days */ + int day_numbers[42]; /* The numbers of the days, as they are shown in the display */ GdkFont *head_font; /* Font for the headings */ GdkFont *day_font; /* Font for the day numbers */ diff --git a/calendar/gui/year-view.c b/calendar/gui/year-view.c index 8a5bedc038..bb3a38ecab 100644 --- a/calendar/gui/year-view.c +++ b/calendar/gui/year-view.c @@ -10,6 +10,7 @@ #include #include "year-view.h" #include "main.h" +#include "timeutil.h" #define HEAD_SPACING 4 /* Spacing between year heading and months */ @@ -19,6 +20,7 @@ static void year_view_class_init (YearViewClass *class); static void year_view_init (YearView *yv); +static void year_view_destroy (GtkObject *object); static void year_view_size_request (GtkWidget *widget, GtkRequisition *requisition); static void year_view_size_allocate (GtkWidget *widget, @@ -54,16 +56,103 @@ year_view_get_type (void) static void year_view_class_init (YearViewClass *class) { + GtkObjectClass *object_class; GtkWidgetClass *widget_class; + object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; parent_class = gtk_type_class (gnome_canvas_get_type ()); + object_class->destroy = year_view_destroy; + widget_class->size_request = year_view_size_request; widget_class->size_allocate = year_view_size_allocate; } +/* Resizes the year view's child items. This is done in the idle loop for performance (we avoid + * resizing on every size allocation). + */ +static gint +idle_handler (gpointer data) +{ + YearView *yv; + double width, height; + double mwidth, mheight; + double h_yofs, m_yofs; + double x, y; + GtkArg arg; + GdkFont *head_font, *title_font; + int i; + + yv = data; + + /* Get the fonts to get their size later */ + + arg.name = "font_gdk"; + gtk_object_getv (GTK_OBJECT (yv->heading), 1, &arg); + head_font = GTK_VALUE_BOXED (arg); + + arg.name = "font_gdk"; + gtk_object_getv (GTK_OBJECT (yv->titles[0]), 1, &arg); + title_font = GTK_VALUE_BOXED (arg); + + /* Adjust heading */ + + gnome_canvas_item_set (yv->heading, + "x", (double) yv->canvas.width / 2.0, + "y", (double) HEAD_SPACING, + NULL); + + /* Adjust months */ + + h_yofs = 2 * HEAD_SPACING + head_font->ascent + head_font->descent; + m_yofs = SPACING + title_font->ascent + title_font->descent; + + width = (yv->canvas.width + SPACING) / 3.0; + height = (yv->canvas.height - h_yofs + SPACING) / 4.0; + + mwidth = (yv->canvas.width - 2 * SPACING) / 3.0; + mheight = (yv->canvas.height - h_yofs - 3 * SPACING - 4 * m_yofs) / 4.0; + + for (i = 0; i < 12; i++) { + x = (i % 3) * width; + y = (i / 3) * height + h_yofs; + + /* Title */ + + gnome_canvas_item_set (yv->titles[i], + "x", x + width / 2.0, + "y", y, + NULL); + + /* Month item */ + + gnome_canvas_item_set (yv->mitems[i], + "x", x, + "y", y + m_yofs, + "width", mwidth, + "height", mheight, + NULL); + } + + /* Done */ + + yv->need_resize = FALSE; + return FALSE; +} + +/* Marks the year view as needing a resize, which will be performed during the idle loop */ +static void +need_resize (YearView *yv) +{ + if (yv->need_resize) + return; + + yv->need_resize = TRUE; + yv->idle_id = gtk_idle_add (idle_handler, yv); +} + static void year_view_init (YearView *yv) { @@ -107,6 +196,30 @@ year_view_init (YearView *yv) "heading_color", "white", NULL); } + + /* We will need to resize the items when we paint for the first time */ + + yv->idle_id = -1; + need_resize (yv); +} + +static void +year_view_destroy (GtkObject *object) +{ + YearView *yv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_YEAR_VIEW (object)); + + yv = YEAR_VIEW (object); + + if (yv->need_resize) { + yv->need_resize = FALSE; + gtk_idle_remove (yv->idle_id); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } GtkWidget * @@ -146,14 +259,6 @@ static void year_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { YearView *yv; - double width, height; - double mwidth, mheight; - double h_yofs; - double m_yofs; - double x, y; - int i; - GtkArg arg; - GdkFont *head_font, *title_font; g_return_if_fail (widget != NULL); g_return_if_fail (IS_YEAR_VIEW (widget)); @@ -165,79 +270,139 @@ year_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); gnome_canvas_set_scroll_region (GNOME_CANVAS (yv), 0, 0, allocation->width, allocation->height); + need_resize (yv); +} - arg.name = "font_gdk"; - gtk_object_getv (GTK_OBJECT (yv->heading), 1, &arg); - head_font = GTK_VALUE_BOXED (arg); +void +year_view_update (YearView *yv, iCalObject *object, int flags) +{ + g_return_if_fail (yv != NULL); + g_return_if_fail (IS_YEAR_VIEW (yv)); - arg.name = "font_gdk"; - gtk_object_getv (GTK_OBJECT (yv->titles[0]), 1, &arg); - title_font = GTK_VALUE_BOXED (arg); + /* If only the summary changed, we don't care */ - /* Adjust heading */ + if (object && ((flags & CHANGE_SUMMARY) == flags)) + return; - gnome_canvas_item_set (yv->heading, - "x", (double) allocation->width / 2.0, - "y", (double) HEAD_SPACING, - NULL); + year_view_set (yv, time_year_begin (yv->year)); +} - /* Adjust months */ +/* Unmarks all the days in the year view by setting their boxes and labels to the default colors */ +static void +unmark_days (YearView *yv) +{ + GnomeCanvasItem *item; + int i, j; - h_yofs = 2 * HEAD_SPACING + head_font->ascent + head_font->descent; - m_yofs = SPACING + title_font->ascent + title_font->descent; + for (i = 0; i < 12; i++) + for (j = 0; j < 42; j++) { + /* Box */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (yv->mitems[i]), + GNOME_MONTH_ITEM_DAY_BOX + j); + gnome_canvas_item_set (item, + "fill_color", "#d6d6d6d6d6d6", + NULL); + + /* Label */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (yv->mitems[i]), + GNOME_MONTH_ITEM_DAY_LABEL + j); + gnome_canvas_item_set (item, + "fill_color", "black", + NULL); + } +} - width = (allocation->width + SPACING) / 3.0; - height = (allocation->height - h_yofs + SPACING) / 4.0; +/* Marks all the days that fall into the specified time span */ +static void +mark_event (YearView *yv, time_t start, time_t end) +{ + time_t t; + struct tm tm; + int day_index; + GnomeCanvasItem *mitem, *item; - mwidth = (allocation->width - 2 * SPACING) / 3.0; - mheight = (allocation->height - h_yofs - 3 * SPACING - 4 * m_yofs) / 4.0; + tm = *localtime (&start); + end = time_end_of_day (end); - for (i = 0; i < 12; i++) { - x = (i % 3) * width; - y = (i / 3) * height + h_yofs; + for (t = start; t < end; t += 60 * 60 * 24) { + mktime (&tm); /* normalize the time */ - /* Title */ + /* We need this comparison because an event may span more than one year (!). + * Yes, this is not the most efficient way of doing this (we could just clip + * the event to the current year), but it will do for now. + */ - gnome_canvas_item_set (yv->titles[i], - "x", x + width / 2.0, - "y", y, - NULL); + if ((tm.tm_year + 1900) == yv->year) { + /* Figure out the month item and day index that correspond to this time */ - /* Month item */ + mitem = yv->mitems[tm.tm_mon]; + day_index = gnome_month_item_day2index (GNOME_MONTH_ITEM (mitem), tm.tm_mday); + g_assert (day_index != -1); - gnome_canvas_item_set (yv->mitems[i], - "x", x, - "y", y + m_yofs, - "width", mwidth, - "height", mheight, - NULL); + /* Mark the day box */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (mitem), + GNOME_MONTH_ITEM_DAY_BOX + day_index); + gnome_canvas_item_set (item, + "fill_color", "tan", + NULL); + + /* Mark the day label */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (mitem), + GNOME_MONTH_ITEM_DAY_LABEL + day_index); + gnome_canvas_item_set (item, + "fill_color", "black", + NULL); + } + + /* Next day */ + + tm.tm_mday++; } } -void -year_view_update (YearView *yv, iCalObject *object, int flags) +/* Queries the calendar for all the events in the current year and marks the days that have at least + * one event in them. + */ +static void +mark_days (YearView *yv) { - g_return_if_fail (yv != NULL); - g_return_if_fail (IS_YEAR_VIEW (yv)); + time_t year_begin, year_end; + GList *list, *l; + CalendarObject *co; + + year_begin = time_year_begin (yv->year); + year_end = time_year_end (yv->year); - /* FIXME */ + list = calendar_get_events_in_range (yv->calendar->cal, year_begin, year_end); + + for (l = list; l; l = l->next) { + co = l->data; + mark_event (yv, co->ev_start, co->ev_end); + } + + calendar_destroy_event_list (list); } void year_view_set (YearView *yv, time_t year) { - struct tm tm; - int i; + struct tm *tm; char buf[100]; + int i; g_return_if_fail (yv != NULL); g_return_if_fail (IS_YEAR_VIEW (yv)); - tm = *localtime (&year); + tm = localtime (&year); + yv->year = tm->tm_year + 1900; /* Heading */ - sprintf (buf, "%d", tm.tm_year + 1900); + sprintf (buf, "%d", yv->year); gnome_canvas_item_set (yv->heading, "text", buf, NULL); @@ -246,11 +411,12 @@ year_view_set (YearView *yv, time_t year) for (i = 0; i < 12; i++) gnome_canvas_item_set (yv->mitems[i], - "year", tm.tm_year + 1900, + "year", yv->year, "month", i, NULL); - /* FIXME: update events */ + unmark_days (yv); + mark_days (yv); } void @@ -266,258 +432,5 @@ year_view_time_format_changed (YearView *yv) "start_on_monday", week_starts_on_monday, NULL); - /* FIXME: update events */ -} - - - - - - - - - - - - - - -#if 0 - -#include "gncal-year-view.h" -#include "calendar.h" -#include "timeutil.h" - -static void gncal_year_view_init (GncalYearView *yview); - -static void -double_click(GtkCalendar *gc, GncalYearView *yview) -{ - struct tm tm; - time_t t; - - tm.tm_mday = gc->selected_day; - tm.tm_mon = gc->month; - tm.tm_year = gc->year - 1900; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - t = mktime (&tm); - - gnome_calendar_dayjump (yview->gcal, t); + year_view_set (yv, time_year_begin (yv->year)); } - -static void -do_nothing(GtkCalendarClass *c) -{ -} - -static void -select_day(GtkWidget *widget, gpointer data) -{ - int i; - - GncalYearView *yview; - - yview = GNCAL_YEAR_VIEW(data); - - for (i = 0; i < 12; i++) - gtk_signal_handler_block(GTK_OBJECT(yview->calendar[i]), - yview->handler[i]); - - for (i = 0; i < 12; i++) - if (GTK_CALENDAR(yview->calendar[i]) != GTK_CALENDAR(widget)) - gtk_calendar_select_day(GTK_CALENDAR(yview->calendar[i]), 0); - - for (i = 0; i < 12; i++) - gtk_signal_handler_unblock(GTK_OBJECT(yview->calendar[i]), - yview->handler[i]); -} - -guint -gncal_year_view_get_type (void) -{ - static guint year_view_type = 0; - - if (!year_view_type) { - GtkTypeInfo year_view_info = { - "GncalYearView", - sizeof (GncalYearView), - sizeof (GncalYearViewClass), - (GtkClassInitFunc) NULL, - (GtkObjectInitFunc) gncal_year_view_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL - }; - - year_view_type = gtk_type_unique (gtk_table_get_type (), - &year_view_info); - } - - return year_view_type; -} - -static void -gncal_year_view_init (GncalYearView *yview) -{ - int i; - - for (i = 0; i < 12; i++) { - yview->calendar[i] = NULL; - yview->handler [i] = 0; - } - - yview->gcal = NULL; - yview->year_label = NULL; - yview->year = 0; -} - -GtkWidget * -gncal_year_view_new (GnomeCalendar *calendar, time_t date) -{ - struct tm my_tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - char monthbuff[40]; - GncalYearView *yview; - GtkWidget *frame, *vbox, *label; - struct tm *tmptm; - int i, x, y; - - yview = gtk_type_new (gncal_year_view_get_type ()); - - tmptm = localtime(&date); - yview->year = tmptm->tm_year; - yview->gcal = calendar; - my_tm.tm_year = tmptm->tm_year; - yview->year_label = gtk_label_new(""); - gtk_table_attach (GTK_TABLE (yview), - GTK_WIDGET (yview->year_label), - 1, 2, - 0, 1, - 0, 0, 0, 5); - gtk_widget_show(GTK_WIDGET(yview->year_label)); - - for (x = 0; x < 3; x++) - for (y = 0; y < 4; y++) { - - i = y * 3 + x; - - yview->calendar[i] = gtk_calendar_new(); - gtk_calendar_display_options(GTK_CALENDAR(yview->calendar[i]), - GTK_CALENDAR_SHOW_DAY_NAMES | - GTK_CALENDAR_NO_MONTH_CHANGE); - frame = gtk_frame_new(NULL); - vbox = gtk_vbox_new(0,0); - - yview->handler[i] = - gtk_signal_connect(GTK_OBJECT(yview->calendar[i]), "day_selected", - GTK_SIGNAL_FUNC(select_day), (gpointer *) yview); - - gtk_signal_connect(GTK_OBJECT(yview->calendar[i]), "day_selected_double_click", - GTK_SIGNAL_FUNC(double_click), (gpointer *) yview); - - my_tm.tm_mon = i; - strftime(monthbuff, 40, "%B", &my_tm); - label = gtk_label_new(monthbuff); - - gtk_container_add(GTK_CONTAINER(frame), vbox); - gtk_box_pack_start(GTK_BOX(vbox), label, 0, 0, 0); - gtk_box_pack_start(GTK_BOX(vbox), yview->calendar[i], 0, 0, 0); - - gtk_table_attach (GTK_TABLE (yview), - GTK_WIDGET (frame), - x, x + 1, - y + 1, y + 2, - 0, 0, 0, 0); - - gtk_widget_show (frame); - gtk_widget_show (vbox); - gtk_widget_show (GTK_WIDGET (yview->calendar[i])); - } - - gncal_year_view_set (yview, date); - - return GTK_WIDGET (yview); -} - -static void -year_view_mark_day (iCalObject *ical, time_t start, time_t end, void *closure) -{ - GncalYearView *yview = (GncalYearView *) closure; - struct tm tm_s; - time_t t, day_end; - - tm_s = *localtime (&start); - day_end = time_end_of_day (end); - - for (t = start; t <= day_end; t+= 60*60*24){ - time_t new = mktime (&tm_s); - struct tm tm_day; - - tm_day = *localtime (&new); - gtk_calendar_mark_day (GTK_CALENDAR (yview->calendar [tm_day.tm_mon]), - tm_day.tm_mday); - tm_s.tm_mday++; - } -} - -static void -gncal_year_view_set_year (GncalYearView *yview, int year) -{ - time_t year_begin, year_end; - char buff[20]; - GList *l; - int i; - - if (!yview->gcal->cal) - return; - - snprintf(buff, 20, "%d", yview->year + 1900); - gtk_label_set(GTK_LABEL(yview->year_label), buff); - - for (i = 0; i < 12; i++) { - gtk_calendar_freeze (GTK_CALENDAR (yview->calendar [i])); - gtk_calendar_select_month (GTK_CALENDAR(yview->calendar[i]), i, yview->year + 1900); - gtk_calendar_clear_marks (GTK_CALENDAR (yview->calendar[i])); - } - - year_begin = time_year_begin (yview->year); - year_end = time_year_end (yview->year); - - l = calendar_get_events_in_range (yview->gcal->cal, year_begin, year_end); - for (; l; l = l->next){ - CalendarObject *co = l->data; - - year_view_mark_day (co->ico, co->ev_start, co->ev_end, yview); - } - for (i = 0; i < 12; i++) - gtk_calendar_thaw (GTK_CALENDAR (yview->calendar [i])); - - calendar_destroy_event_list (l); -} - -void -gncal_year_view_set (GncalYearView *yview, time_t date) -{ - struct tm *tmptm; - - tmptm = localtime(&date); - yview->year = tmptm->tm_year; - - gncal_year_view_set_year (yview, yview->year); -} - -void -gncal_year_view_update (GncalYearView *yview, iCalObject *ico, int flags) -{ - g_return_if_fail (yview != NULL); - g_return_if_fail (GNCAL_IS_YEAR_VIEW (yview)); - - /* If only the summary changed, we dont care */ - if (flags && (flags & CHANGE_SUMMARY) == flags) - return; - - gncal_year_view_set_year (yview, yview->year); -} - -#endif diff --git a/calendar/gui/year-view.h b/calendar/gui/year-view.h index 0638698fb4..fa0b4ed65c 100644 --- a/calendar/gui/year-view.h +++ b/calendar/gui/year-view.h @@ -32,9 +32,15 @@ struct _YearView { GnomeCalendar *calendar; /* The calendar we are associated to */ + int year; /* The year we are displaying */ + GnomeCanvasItem *heading; /* Big heading with year */ GnomeCanvasItem *titles[12]; /* Titles for months */ GnomeCanvasItem *mitems[12]; /* Month items */ + + guint idle_id; /* ID of idle handler for resize */ + + int need_resize : 1; /* Specifies whether we need to resize the canvas items or not */ }; struct _YearViewClass { diff --git a/calendar/timeutil.c b/calendar/timeutil.c index 03d9465daa..670a29609b 100644 --- a/calendar/timeutil.c +++ b/calendar/timeutil.c @@ -221,7 +221,7 @@ time_year_begin (int year) tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; - tm.tm_year = year; + tm.tm_year = year - 1900; tm.tm_mon = 0; tm.tm_mday = 1; tm.tm_isdst = -1; @@ -238,7 +238,7 @@ time_year_end (int year) tm.tm_hour = 23; tm.tm_min = 59; tm.tm_sec = 59; - tm.tm_year = year; + tm.tm_year = year - 1900; tm.tm_mon = 11; tm.tm_mday = 31; tm.tm_isdst = -1; diff --git a/calendar/year-view.c b/calendar/year-view.c index 8a5bedc038..bb3a38ecab 100644 --- a/calendar/year-view.c +++ b/calendar/year-view.c @@ -10,6 +10,7 @@ #include #include "year-view.h" #include "main.h" +#include "timeutil.h" #define HEAD_SPACING 4 /* Spacing between year heading and months */ @@ -19,6 +20,7 @@ static void year_view_class_init (YearViewClass *class); static void year_view_init (YearView *yv); +static void year_view_destroy (GtkObject *object); static void year_view_size_request (GtkWidget *widget, GtkRequisition *requisition); static void year_view_size_allocate (GtkWidget *widget, @@ -54,16 +56,103 @@ year_view_get_type (void) static void year_view_class_init (YearViewClass *class) { + GtkObjectClass *object_class; GtkWidgetClass *widget_class; + object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; parent_class = gtk_type_class (gnome_canvas_get_type ()); + object_class->destroy = year_view_destroy; + widget_class->size_request = year_view_size_request; widget_class->size_allocate = year_view_size_allocate; } +/* Resizes the year view's child items. This is done in the idle loop for performance (we avoid + * resizing on every size allocation). + */ +static gint +idle_handler (gpointer data) +{ + YearView *yv; + double width, height; + double mwidth, mheight; + double h_yofs, m_yofs; + double x, y; + GtkArg arg; + GdkFont *head_font, *title_font; + int i; + + yv = data; + + /* Get the fonts to get their size later */ + + arg.name = "font_gdk"; + gtk_object_getv (GTK_OBJECT (yv->heading), 1, &arg); + head_font = GTK_VALUE_BOXED (arg); + + arg.name = "font_gdk"; + gtk_object_getv (GTK_OBJECT (yv->titles[0]), 1, &arg); + title_font = GTK_VALUE_BOXED (arg); + + /* Adjust heading */ + + gnome_canvas_item_set (yv->heading, + "x", (double) yv->canvas.width / 2.0, + "y", (double) HEAD_SPACING, + NULL); + + /* Adjust months */ + + h_yofs = 2 * HEAD_SPACING + head_font->ascent + head_font->descent; + m_yofs = SPACING + title_font->ascent + title_font->descent; + + width = (yv->canvas.width + SPACING) / 3.0; + height = (yv->canvas.height - h_yofs + SPACING) / 4.0; + + mwidth = (yv->canvas.width - 2 * SPACING) / 3.0; + mheight = (yv->canvas.height - h_yofs - 3 * SPACING - 4 * m_yofs) / 4.0; + + for (i = 0; i < 12; i++) { + x = (i % 3) * width; + y = (i / 3) * height + h_yofs; + + /* Title */ + + gnome_canvas_item_set (yv->titles[i], + "x", x + width / 2.0, + "y", y, + NULL); + + /* Month item */ + + gnome_canvas_item_set (yv->mitems[i], + "x", x, + "y", y + m_yofs, + "width", mwidth, + "height", mheight, + NULL); + } + + /* Done */ + + yv->need_resize = FALSE; + return FALSE; +} + +/* Marks the year view as needing a resize, which will be performed during the idle loop */ +static void +need_resize (YearView *yv) +{ + if (yv->need_resize) + return; + + yv->need_resize = TRUE; + yv->idle_id = gtk_idle_add (idle_handler, yv); +} + static void year_view_init (YearView *yv) { @@ -107,6 +196,30 @@ year_view_init (YearView *yv) "heading_color", "white", NULL); } + + /* We will need to resize the items when we paint for the first time */ + + yv->idle_id = -1; + need_resize (yv); +} + +static void +year_view_destroy (GtkObject *object) +{ + YearView *yv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_YEAR_VIEW (object)); + + yv = YEAR_VIEW (object); + + if (yv->need_resize) { + yv->need_resize = FALSE; + gtk_idle_remove (yv->idle_id); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } GtkWidget * @@ -146,14 +259,6 @@ static void year_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { YearView *yv; - double width, height; - double mwidth, mheight; - double h_yofs; - double m_yofs; - double x, y; - int i; - GtkArg arg; - GdkFont *head_font, *title_font; g_return_if_fail (widget != NULL); g_return_if_fail (IS_YEAR_VIEW (widget)); @@ -165,79 +270,139 @@ year_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); gnome_canvas_set_scroll_region (GNOME_CANVAS (yv), 0, 0, allocation->width, allocation->height); + need_resize (yv); +} - arg.name = "font_gdk"; - gtk_object_getv (GTK_OBJECT (yv->heading), 1, &arg); - head_font = GTK_VALUE_BOXED (arg); +void +year_view_update (YearView *yv, iCalObject *object, int flags) +{ + g_return_if_fail (yv != NULL); + g_return_if_fail (IS_YEAR_VIEW (yv)); - arg.name = "font_gdk"; - gtk_object_getv (GTK_OBJECT (yv->titles[0]), 1, &arg); - title_font = GTK_VALUE_BOXED (arg); + /* If only the summary changed, we don't care */ - /* Adjust heading */ + if (object && ((flags & CHANGE_SUMMARY) == flags)) + return; - gnome_canvas_item_set (yv->heading, - "x", (double) allocation->width / 2.0, - "y", (double) HEAD_SPACING, - NULL); + year_view_set (yv, time_year_begin (yv->year)); +} - /* Adjust months */ +/* Unmarks all the days in the year view by setting their boxes and labels to the default colors */ +static void +unmark_days (YearView *yv) +{ + GnomeCanvasItem *item; + int i, j; - h_yofs = 2 * HEAD_SPACING + head_font->ascent + head_font->descent; - m_yofs = SPACING + title_font->ascent + title_font->descent; + for (i = 0; i < 12; i++) + for (j = 0; j < 42; j++) { + /* Box */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (yv->mitems[i]), + GNOME_MONTH_ITEM_DAY_BOX + j); + gnome_canvas_item_set (item, + "fill_color", "#d6d6d6d6d6d6", + NULL); + + /* Label */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (yv->mitems[i]), + GNOME_MONTH_ITEM_DAY_LABEL + j); + gnome_canvas_item_set (item, + "fill_color", "black", + NULL); + } +} - width = (allocation->width + SPACING) / 3.0; - height = (allocation->height - h_yofs + SPACING) / 4.0; +/* Marks all the days that fall into the specified time span */ +static void +mark_event (YearView *yv, time_t start, time_t end) +{ + time_t t; + struct tm tm; + int day_index; + GnomeCanvasItem *mitem, *item; - mwidth = (allocation->width - 2 * SPACING) / 3.0; - mheight = (allocation->height - h_yofs - 3 * SPACING - 4 * m_yofs) / 4.0; + tm = *localtime (&start); + end = time_end_of_day (end); - for (i = 0; i < 12; i++) { - x = (i % 3) * width; - y = (i / 3) * height + h_yofs; + for (t = start; t < end; t += 60 * 60 * 24) { + mktime (&tm); /* normalize the time */ - /* Title */ + /* We need this comparison because an event may span more than one year (!). + * Yes, this is not the most efficient way of doing this (we could just clip + * the event to the current year), but it will do for now. + */ - gnome_canvas_item_set (yv->titles[i], - "x", x + width / 2.0, - "y", y, - NULL); + if ((tm.tm_year + 1900) == yv->year) { + /* Figure out the month item and day index that correspond to this time */ - /* Month item */ + mitem = yv->mitems[tm.tm_mon]; + day_index = gnome_month_item_day2index (GNOME_MONTH_ITEM (mitem), tm.tm_mday); + g_assert (day_index != -1); - gnome_canvas_item_set (yv->mitems[i], - "x", x, - "y", y + m_yofs, - "width", mwidth, - "height", mheight, - NULL); + /* Mark the day box */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (mitem), + GNOME_MONTH_ITEM_DAY_BOX + day_index); + gnome_canvas_item_set (item, + "fill_color", "tan", + NULL); + + /* Mark the day label */ + + item = gnome_month_item_num2child (GNOME_MONTH_ITEM (mitem), + GNOME_MONTH_ITEM_DAY_LABEL + day_index); + gnome_canvas_item_set (item, + "fill_color", "black", + NULL); + } + + /* Next day */ + + tm.tm_mday++; } } -void -year_view_update (YearView *yv, iCalObject *object, int flags) +/* Queries the calendar for all the events in the current year and marks the days that have at least + * one event in them. + */ +static void +mark_days (YearView *yv) { - g_return_if_fail (yv != NULL); - g_return_if_fail (IS_YEAR_VIEW (yv)); + time_t year_begin, year_end; + GList *list, *l; + CalendarObject *co; + + year_begin = time_year_begin (yv->year); + year_end = time_year_end (yv->year); - /* FIXME */ + list = calendar_get_events_in_range (yv->calendar->cal, year_begin, year_end); + + for (l = list; l; l = l->next) { + co = l->data; + mark_event (yv, co->ev_start, co->ev_end); + } + + calendar_destroy_event_list (list); } void year_view_set (YearView *yv, time_t year) { - struct tm tm; - int i; + struct tm *tm; char buf[100]; + int i; g_return_if_fail (yv != NULL); g_return_if_fail (IS_YEAR_VIEW (yv)); - tm = *localtime (&year); + tm = localtime (&year); + yv->year = tm->tm_year + 1900; /* Heading */ - sprintf (buf, "%d", tm.tm_year + 1900); + sprintf (buf, "%d", yv->year); gnome_canvas_item_set (yv->heading, "text", buf, NULL); @@ -246,11 +411,12 @@ year_view_set (YearView *yv, time_t year) for (i = 0; i < 12; i++) gnome_canvas_item_set (yv->mitems[i], - "year", tm.tm_year + 1900, + "year", yv->year, "month", i, NULL); - /* FIXME: update events */ + unmark_days (yv); + mark_days (yv); } void @@ -266,258 +432,5 @@ year_view_time_format_changed (YearView *yv) "start_on_monday", week_starts_on_monday, NULL); - /* FIXME: update events */ -} - - - - - - - - - - - - - - -#if 0 - -#include "gncal-year-view.h" -#include "calendar.h" -#include "timeutil.h" - -static void gncal_year_view_init (GncalYearView *yview); - -static void -double_click(GtkCalendar *gc, GncalYearView *yview) -{ - struct tm tm; - time_t t; - - tm.tm_mday = gc->selected_day; - tm.tm_mon = gc->month; - tm.tm_year = gc->year - 1900; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - t = mktime (&tm); - - gnome_calendar_dayjump (yview->gcal, t); + year_view_set (yv, time_year_begin (yv->year)); } - -static void -do_nothing(GtkCalendarClass *c) -{ -} - -static void -select_day(GtkWidget *widget, gpointer data) -{ - int i; - - GncalYearView *yview; - - yview = GNCAL_YEAR_VIEW(data); - - for (i = 0; i < 12; i++) - gtk_signal_handler_block(GTK_OBJECT(yview->calendar[i]), - yview->handler[i]); - - for (i = 0; i < 12; i++) - if (GTK_CALENDAR(yview->calendar[i]) != GTK_CALENDAR(widget)) - gtk_calendar_select_day(GTK_CALENDAR(yview->calendar[i]), 0); - - for (i = 0; i < 12; i++) - gtk_signal_handler_unblock(GTK_OBJECT(yview->calendar[i]), - yview->handler[i]); -} - -guint -gncal_year_view_get_type (void) -{ - static guint year_view_type = 0; - - if (!year_view_type) { - GtkTypeInfo year_view_info = { - "GncalYearView", - sizeof (GncalYearView), - sizeof (GncalYearViewClass), - (GtkClassInitFunc) NULL, - (GtkObjectInitFunc) gncal_year_view_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL - }; - - year_view_type = gtk_type_unique (gtk_table_get_type (), - &year_view_info); - } - - return year_view_type; -} - -static void -gncal_year_view_init (GncalYearView *yview) -{ - int i; - - for (i = 0; i < 12; i++) { - yview->calendar[i] = NULL; - yview->handler [i] = 0; - } - - yview->gcal = NULL; - yview->year_label = NULL; - yview->year = 0; -} - -GtkWidget * -gncal_year_view_new (GnomeCalendar *calendar, time_t date) -{ - struct tm my_tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - char monthbuff[40]; - GncalYearView *yview; - GtkWidget *frame, *vbox, *label; - struct tm *tmptm; - int i, x, y; - - yview = gtk_type_new (gncal_year_view_get_type ()); - - tmptm = localtime(&date); - yview->year = tmptm->tm_year; - yview->gcal = calendar; - my_tm.tm_year = tmptm->tm_year; - yview->year_label = gtk_label_new(""); - gtk_table_attach (GTK_TABLE (yview), - GTK_WIDGET (yview->year_label), - 1, 2, - 0, 1, - 0, 0, 0, 5); - gtk_widget_show(GTK_WIDGET(yview->year_label)); - - for (x = 0; x < 3; x++) - for (y = 0; y < 4; y++) { - - i = y * 3 + x; - - yview->calendar[i] = gtk_calendar_new(); - gtk_calendar_display_options(GTK_CALENDAR(yview->calendar[i]), - GTK_CALENDAR_SHOW_DAY_NAMES | - GTK_CALENDAR_NO_MONTH_CHANGE); - frame = gtk_frame_new(NULL); - vbox = gtk_vbox_new(0,0); - - yview->handler[i] = - gtk_signal_connect(GTK_OBJECT(yview->calendar[i]), "day_selected", - GTK_SIGNAL_FUNC(select_day), (gpointer *) yview); - - gtk_signal_connect(GTK_OBJECT(yview->calendar[i]), "day_selected_double_click", - GTK_SIGNAL_FUNC(double_click), (gpointer *) yview); - - my_tm.tm_mon = i; - strftime(monthbuff, 40, "%B", &my_tm); - label = gtk_label_new(monthbuff); - - gtk_container_add(GTK_CONTAINER(frame), vbox); - gtk_box_pack_start(GTK_BOX(vbox), label, 0, 0, 0); - gtk_box_pack_start(GTK_BOX(vbox), yview->calendar[i], 0, 0, 0); - - gtk_table_attach (GTK_TABLE (yview), - GTK_WIDGET (frame), - x, x + 1, - y + 1, y + 2, - 0, 0, 0, 0); - - gtk_widget_show (frame); - gtk_widget_show (vbox); - gtk_widget_show (GTK_WIDGET (yview->calendar[i])); - } - - gncal_year_view_set (yview, date); - - return GTK_WIDGET (yview); -} - -static void -year_view_mark_day (iCalObject *ical, time_t start, time_t end, void *closure) -{ - GncalYearView *yview = (GncalYearView *) closure; - struct tm tm_s; - time_t t, day_end; - - tm_s = *localtime (&start); - day_end = time_end_of_day (end); - - for (t = start; t <= day_end; t+= 60*60*24){ - time_t new = mktime (&tm_s); - struct tm tm_day; - - tm_day = *localtime (&new); - gtk_calendar_mark_day (GTK_CALENDAR (yview->calendar [tm_day.tm_mon]), - tm_day.tm_mday); - tm_s.tm_mday++; - } -} - -static void -gncal_year_view_set_year (GncalYearView *yview, int year) -{ - time_t year_begin, year_end; - char buff[20]; - GList *l; - int i; - - if (!yview->gcal->cal) - return; - - snprintf(buff, 20, "%d", yview->year + 1900); - gtk_label_set(GTK_LABEL(yview->year_label), buff); - - for (i = 0; i < 12; i++) { - gtk_calendar_freeze (GTK_CALENDAR (yview->calendar [i])); - gtk_calendar_select_month (GTK_CALENDAR(yview->calendar[i]), i, yview->year + 1900); - gtk_calendar_clear_marks (GTK_CALENDAR (yview->calendar[i])); - } - - year_begin = time_year_begin (yview->year); - year_end = time_year_end (yview->year); - - l = calendar_get_events_in_range (yview->gcal->cal, year_begin, year_end); - for (; l; l = l->next){ - CalendarObject *co = l->data; - - year_view_mark_day (co->ico, co->ev_start, co->ev_end, yview); - } - for (i = 0; i < 12; i++) - gtk_calendar_thaw (GTK_CALENDAR (yview->calendar [i])); - - calendar_destroy_event_list (l); -} - -void -gncal_year_view_set (GncalYearView *yview, time_t date) -{ - struct tm *tmptm; - - tmptm = localtime(&date); - yview->year = tmptm->tm_year; - - gncal_year_view_set_year (yview, yview->year); -} - -void -gncal_year_view_update (GncalYearView *yview, iCalObject *ico, int flags) -{ - g_return_if_fail (yview != NULL); - g_return_if_fail (GNCAL_IS_YEAR_VIEW (yview)); - - /* If only the summary changed, we dont care */ - if (flags && (flags & CHANGE_SUMMARY) == flags) - return; - - gncal_year_view_set_year (yview, yview->year); -} - -#endif diff --git a/calendar/year-view.h b/calendar/year-view.h index 0638698fb4..fa0b4ed65c 100644 --- a/calendar/year-view.h +++ b/calendar/year-view.h @@ -32,9 +32,15 @@ struct _YearView { GnomeCalendar *calendar; /* The calendar we are associated to */ + int year; /* The year we are displaying */ + GnomeCanvasItem *heading; /* Big heading with year */ GnomeCanvasItem *titles[12]; /* Titles for months */ GnomeCanvasItem *mitems[12]; /* Month items */ + + guint idle_id; /* ID of idle handler for resize */ + + int need_resize : 1; /* Specifies whether we need to resize the canvas items or not */ }; struct _YearViewClass { -- cgit v1.2.3