diff options
-rw-r--r-- | calendar/ChangeLog | 28 | ||||
-rw-r--r-- | calendar/TODO | 22 | ||||
-rw-r--r-- | calendar/calendar.h | 12 | ||||
-rw-r--r-- | calendar/gnome-month-item.c | 16 | ||||
-rw-r--r-- | calendar/gnome-month-item.h | 2 | ||||
-rw-r--r-- | calendar/gui/calendar.h | 12 | ||||
-rw-r--r-- | calendar/gui/gnome-month-item.c | 16 | ||||
-rw-r--r-- | calendar/gui/gnome-month-item.h | 2 | ||||
-rw-r--r-- | calendar/gui/year-view.c | 525 | ||||
-rw-r--r-- | calendar/gui/year-view.h | 6 | ||||
-rw-r--r-- | calendar/timeutil.c | 4 | ||||
-rw-r--r-- | calendar/year-view.c | 525 | ||||
-rw-r--r-- | calendar/year-view.h | 6 |
13 files changed, 531 insertions, 645 deletions
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 <federico@nuclecu.unam.mx> + + * 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 <federico@nuclecu.unam.mx> * 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 <libgnomeui/gnome-canvas-text.h> #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 <libgnomeui/gnome-canvas-text.h> #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 { |