diff options
-rw-r--r-- | calendar/ChangeLog | 14 | ||||
-rw-r--r-- | calendar/gui/calendar-model.c | 480 |
2 files changed, 298 insertions, 196 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index b96f3fbc3e..fed48a1b24 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,17 @@ +2000-08-21 Federico Mena Quintero <federico@helixcode.com> + + * gui/calendar-model.c (set_categories): New function. + (parse_time): Moved over from the old set_time_t(). This just + parses the time and leaves the warning dialog for the caller. + (set_datetime): New function. + (set_geo): Updated old function. + (set_percent): Updated old function. + (set_priority): Updated old function. + (set_summary): New function. + (set_url): New function. + (calendar_model_set_value_at): Updated function. + (calendar_model_is_cell_editable): Updated function. + 2000-08-21 JP Rosevear <jpr@helixcode.com> * gui/e-week-view.c (e_week_view_reload_events): diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c index daa85ddcd6..cc05d1dea7 100644 --- a/calendar/gui/calendar-model.c +++ b/calendar/gui/calendar-model.c @@ -26,13 +26,13 @@ #include <config.h> #include <ctype.h> +#include <math.h> #undef _XOPEN_SOURCE #include <sys/time.h> #define _XOPEN_SOURCE #include <time.h> -#include <gtk/gtksignal.h> -#include <libgnomeui/gnome-messagebox.h> -#include <libgnomeui/gnome-stock.h> +#include <gnome.h> +#include <cal-util/timeutil.h> #include "calendar-model.h" #include "calendar-commands.h" @@ -253,6 +253,7 @@ calendar_model_row_count (ETableModel *etm) return priv->objects->len; } +/* Creates a nice string representation of a time value */ static char* get_time_t (time_t *t, gboolean skip_midnight) { @@ -301,7 +302,7 @@ get_categories (CalComponent *comp) s = str->str; - g_string_free (s, FALSE); + g_string_free (str, FALSE); cal_component_free_categories_list (categories); return s; @@ -365,9 +366,9 @@ get_and_free_datetime (CalComponentDateTime dt) if (!dt.value) t = 0; else - t = time_from_icaltimetype (*t.value); + t = time_from_icaltimetype (*dt.value); - cal_component_free_datetime (comp, &dt); + cal_component_free_datetime (&dt); return get_time_t (&t, FALSE); } @@ -402,7 +403,7 @@ get_due (CalComponent *comp) return get_and_free_datetime (dt); } -/* Builds a string for the PERCENT property of a calendar component */ +/* Builds a string for the GEO property of a calendar component */ static char* get_geo (CalComponent *comp) { @@ -467,7 +468,7 @@ get_priority (CalComponent *comp) static char * get_summary (CalComponent *comp) { - CalComponentSummary summary; + CalComponentText summary; cal_component_get_summary (comp, &summary); @@ -595,7 +596,7 @@ get_is_overdue (CalComponent *comp) t = time_from_icaltimetype (*dt.value); - if (dt < time (NULL)) + if (t < time (NULL)) retval = TRUE; else retval = FALSE; @@ -615,7 +616,6 @@ calendar_model_value_at (ETableModel *etm, int col, int row) CalendarModel *model; CalendarModelPrivate *priv; CalComponent *comp; - static char buffer[16]; model = CALENDAR_MODEL (etm); priv = model->priv; @@ -695,20 +695,7 @@ calendar_model_value_at (ETableModel *etm, int col, int row) } } -/* Replaces a string */ -static void -set_string (char **dest, const char *value) -{ - if (*dest) - g_free (*dest); - - if (value) - *dest = g_strdup (value); - else - *dest = NULL; -} - - +/* Returns whether a string is NULL, empty, or full of whitespace */ static gboolean string_is_empty (const char *value) { @@ -732,7 +719,7 @@ string_is_empty (const char *value) /* FIXME: We need to set the "transient_for" property for the dialog, but the model doesn't know anything about the windows. */ static void -show_date_warning () +show_date_warning (void) { GtkWidget *dialog; char buffer[32], message[256]; @@ -753,172 +740,302 @@ show_date_warning () gtk_widget_show (dialog); } +/* Builds a list of categories from a comma-delimited string */ +static GSList * +categories_from_string (const char *value) +{ + GSList *list; + const char *categ_start; + const char *categ_end; + const char *p; + + if (!value) + return NULL; + + list = NULL; + + categ_start = categ_end = NULL; + + for (p = value; *p; p++) { + if (categ_start) { + if (*p == ',') { + char *c; + + c = g_strndup (categ_start, categ_end - categ_start + 1); + list = g_slist_prepend (list, c); -/* Replaces a time_t value */ + categ_start = categ_end = NULL; + } else if (!isspace (*p)) + categ_end = p; + } else if (!isspace (*p) && *p != ',') + categ_start = categ_end = p; + } + + if (categ_start) { + char *c; + + c = g_strndup (categ_start, categ_end - categ_start + 1); + list = g_slist_prepend (list, c); + } + + return g_slist_reverse (list); +} + +/* Sets the list of categories from a comma-delimited string */ static void -set_time_t (time_t *dest, const char *value) +set_categories (CalComponent *comp, const char *value) +{ + GSList *list; + GSList *l; + + list = categories_from_string (value); + + cal_component_set_categories_list (comp, list); + + for (l = list; l; l = l->next) { + char *s; + + s = l->data; + g_free (s); + } + + g_slist_free (list); +} + +/* Parses a time value entered by the user; returns -1 if it could not be + * parsed. Returns 0 for an empty time. + */ +static time_t +parse_time (const char *value) { struct tm tmp_tm; struct tm *today_tm; time_t t; const char *p; - if (string_is_empty (value)) { - *dest = 0; - } else { - /* Skip any weekday name. */ - p = strptime (value, "%a", &tmp_tm); - if (!p) - p = value; - - /* Try to match the full date & time, or without the seconds, - or just the date, or just the time with/without seconds. - The info pages say we should clear the tm before calling - strptime. It also means that if we don't match a time we - get 00:00:00 which is good. */ + if (string_is_empty (value)) + return 0; + + /* Skip any weekday name. */ + p = strptime (value, "%a", &tmp_tm); + if (!p) + p = value; + + /* Try to match the full date & time, or without the seconds, + or just the date, or just the time with/without seconds. + The info pages say we should clear the tm before calling + strptime. It also means that if we don't match a time we + get 00:00:00 which is good. */ + memset (&tmp_tm, 0, sizeof (tmp_tm)); + if (!strptime (value, "%x %T", &tmp_tm)) { memset (&tmp_tm, 0, sizeof (tmp_tm)); - if (!strptime (value, "%x %T", &tmp_tm)) { + if (!strptime (value, "%x %H:%M", &tmp_tm)) { memset (&tmp_tm, 0, sizeof (tmp_tm)); - if (!strptime (value, "%x %H:%M", &tmp_tm)) { + if (!strptime (value, "%x", &tmp_tm)) { memset (&tmp_tm, 0, sizeof (tmp_tm)); - if (!strptime (value, "%x", &tmp_tm)) { + if (!strptime (value, "%T", &tmp_tm)) { memset (&tmp_tm, 0, sizeof (tmp_tm)); - if (!strptime (value, "%T", &tmp_tm)) { - memset (&tmp_tm, 0, sizeof (tmp_tm)); - if (!strptime (value, "%H:%M", &tmp_tm)) { - - g_warning ("Couldn't parse date string"); - show_date_warning (); - return; - } - } - - /* We only got a time, so we use the - current day. */ - t = time (NULL); - today_tm = localtime (&t); - tmp_tm.tm_mday = today_tm->tm_mday; - tmp_tm.tm_mon = today_tm->tm_mon; - tmp_tm.tm_year = today_tm->tm_year; + if (!strptime (value, "%H:%M", &tmp_tm)) + return -1; /* Could not parse it */ } + + /* We only got a time, so we use the + current day. */ + t = time (NULL); + today_tm = localtime (&t); + tmp_tm.tm_mday = today_tm->tm_mday; + tmp_tm.tm_mon = today_tm->tm_mon; + tmp_tm.tm_year = today_tm->tm_year; } } + } + + tmp_tm.tm_isdst = -1; + return mktime (&tmp_tm); +} + +/* Sets the completion time of a component */ +static void +set_completed (CalComponent *comp, const char *value) +{ + time_t t; + struct icaltimetype itt; - tmp_tm.tm_isdst = -1; - *dest = mktime (&tmp_tm); + t = parse_time (value); + if (t == -1) { + show_date_warning (); + return; + } else if (t == 0) { + cal_component_set_completed (comp, NULL); + return; + } else { + itt = icaltimetype_from_timet (t, FALSE); + cal_component_set_completed (comp, &itt); } } +/* Sets a CalComponentDateTime value */ +static void +set_datetime (CalComponent *comp, const char *value, + void (* set_func) (CalComponent *comp, CalComponentDateTime *dt)) +{ + time_t t; -/* FIXME: We need to set the "transient_for" property for the dialog, but - the model doesn't know anything about the windows. */ + t = parse_time (value); + if (t == -1) { + show_date_warning (); + return; + } else if (t == 0) { + (* set_func) (comp, NULL); + return; + } else { + CalComponentDateTime dt; + struct icaltimetype itt; + + itt = icaltimetype_from_timet (t, FALSE); + dt.value = &itt; + dt.tzid = NULL; + + (* set_func) (comp, &dt); + } +} + +/* FIXME: We need to set the "transient_for" property for the dialog, but the + * model doesn't know anything about the windows. + */ static void -show_geo_warning () +show_geo_warning (void) { GtkWidget *dialog; - dialog = gnome_message_box_new (_("The geographical position must be entered in the format: \n\n45.436845,125.862501"), + dialog = gnome_message_box_new (_("The geographical position must be entered " + "in the format: \n\n45.436845,125.862501"), GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gtk_widget_show (dialog); } - -/* Replaces a geo value */ +/* Sets the geographical position value of a component */ static void -set_geo (iCalGeo *dest, const char *value) +set_geo (CalComponent *comp, const char *value) { double latitude, longitude; - gint matched; + int matched; + struct icalgeotype geo; - if (!string_is_empty (value)) { - matched = sscanf (value, "%lg , %lg", &latitude, &longitude); + if (string_is_empty (value)) { + cal_component_set_geo (comp, NULL); + return; + } - if (matched != 2) { - show_geo_warning (); - } else { - dest->valid = TRUE; - dest->latitude = latitude; - dest->longitude = longitude; - } - } else { - dest->valid = FALSE; - dest->latitude = 0.0; - dest->longitude = 0.0; + matched = sscanf (value, "%lg , %lg", &latitude, &longitude); + + if (matched != 2) { + show_geo_warning (); + return; } -} -/* Replaces a person value */ -static void -set_person (iCalPerson **dest, const iCalPerson *value) -{ - /* FIXME: This can't be set at present so it shouldn't be called. */ + geo.lat = latitude; + geo.lon = longitude; + cal_component_set_geo (comp, &geo); } -/* FIXME: We need to set the "transient_for" property for the dialog, but - the model doesn't know anything about the windows. */ +/* FIXME: We need to set the "transient_for" property for the dialog, but the + * model doesn't know anything about the windows. + */ static void -show_percent_warning () +show_percent_warning (void) { GtkWidget *dialog; - dialog = gnome_message_box_new (_("The percent value must be between 0 and 100"), + dialog = gnome_message_box_new (_("The percent value must be between 0 and 100, inclusive"), GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gtk_widget_show (dialog); } - -/* Sets an int value */ +/* Sets the percent value of a calendar component */ static void -set_percent (int *dest, const char *value) +set_percent (CalComponent *comp, const char *value) { - gint matched, percent; + int matched, percent; - if (!string_is_empty (value)) { - matched = sscanf (value, "%i", &percent); + if (string_is_empty (value)) { + cal_component_set_percent (comp, NULL); + return; + } - if (matched != 1 || percent < 0 || percent > 100) { - show_percent_warning (); - } else { - *dest = percent; - } - } else { - *dest = 0; + matched = sscanf (value, "%i", &percent); + + if (matched != 1 || percent < 0 || percent > 100) { + show_percent_warning (); + return; } + + cal_component_set_percent (comp, &percent); } -/* FIXME: We need to set the "transient_for" property for the dialog, but - the model doesn't know anything about the windows. */ +/* FIXME: We need to set the "transient_for" property for the dialog, but the + * model doesn't know anything about the windows. */ static void -show_priority_warning () +show_priority_warning (void) { GtkWidget *dialog; - dialog = gnome_message_box_new (_("The priority must be between 0 and 10"), + dialog = gnome_message_box_new (_("The priority must be between 1 and 9, inclusive"), GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gtk_widget_show (dialog); } +/* Sets the priority of a calendar component */ +static void +set_priority (CalComponent *comp, const char *value) +{ + int matched, priority; + + if (string_is_empty (value)) { + cal_component_set_priority (comp, NULL); + return; + } + + matched = sscanf (value, "%i", &priority); -/* Sets an int value */ + if (matched != 1 || priority < 1 || priority > 9) { + show_priority_warning (); + return; + } + + cal_component_set_priority (comp, &priority); +} + +/* Sets the summary of a calendar component */ static void -set_priority (int *dest, const char *value) +set_summary (CalComponent *comp, const char *value) { - gint matched, priority; + CalComponentText text; + + if (string_is_empty (value)) { + cal_component_set_summary (comp, NULL); + return; + } - if (!string_is_empty (value)) { - matched = sscanf (value, "%i", &priority); + text.value = value; + text.altrep = NULL; /* FIXME: should we preserve the old ALTREP? */ - if (matched != 1 || priority < 0 || priority > 10) { - show_priority_warning (); - } else { - *dest = priority; - } - } else { - *dest = 0; + cal_component_set_summary (comp, &text); +} + +/* Sets the URI of a calendar component */ +static void +set_url (CalComponent *comp, const char *value) +{ + if (string_is_empty (value)) { + cal_component_set_url (comp, NULL); + return; } + + cal_component_set_url (comp, value); } /* set_value_at handler for the calendar table model */ @@ -927,93 +1044,62 @@ calendar_model_set_value_at (ETableModel *etm, int col, int row, const void *val { CalendarModel *model; CalendarModelPrivate *priv; - iCalObject *ico; + CalComponent *comp; model = CALENDAR_MODEL (etm); priv = model->priv; - g_return_if_fail (col >= 0 && col < ICAL_OBJECT_FIELD_NUM_FIELDS); + g_return_if_fail (col >= 0 && col < CAL_COMPONENT_FIELD_NUM_FIELDS); g_return_if_fail (row >= 0 && row < priv->objects->len); - ico = g_array_index (priv->objects, iCalObject *, row); - g_assert (ico != NULL); + comp = g_array_index (priv->objects, CalComponent *, row); + g_assert (comp != NULL); switch (col) { - case ICAL_OBJECT_FIELD_COMMENT: - set_string (&ico->comment, value); - break; - - case ICAL_OBJECT_FIELD_COMPLETED: - /* FIXME: Set status, percent etc. fields as well. */ - set_time_t (&ico->completed, value); - break; - - case ICAL_OBJECT_FIELD_DESCRIPTION: - set_string (&ico->desc, value); - break; - - case ICAL_OBJECT_FIELD_DTSTAMP: - set_time_t (&ico->dtstamp, value); - break; - - case ICAL_OBJECT_FIELD_DTSTART: - set_time_t (&ico->dtstart, value); + case CAL_COMPONENT_FIELD_CATEGORIES: + set_categories (comp, value); break; - case ICAL_OBJECT_FIELD_DTEND: - set_time_t (&ico->dtend, value); - break; + /* FIXME: CLASSIFICATION requires an option menu cell renderer */ - case ICAL_OBJECT_FIELD_GEO: - set_geo (&ico->geo, value); + case CAL_COMPONENT_FIELD_COMPLETED: + set_completed (comp, value); break; - case ICAL_OBJECT_FIELD_LAST_MOD: - set_time_t (&ico->last_mod, value); + case CAL_COMPONENT_FIELD_DTEND: + /* FIXME: Need to reset dtstart if dtend happens before it */ + set_datetime (comp, value, cal_component_set_dtend); break; - case ICAL_OBJECT_FIELD_LOCATION: - set_string (&ico->location, value); + case CAL_COMPONENT_FIELD_DTSTART: + /* FIXME: Need to reset dtend if dtstart happens after it */ + set_datetime (comp, value, cal_component_set_dtstart); break; - case ICAL_OBJECT_FIELD_ORGANIZER: - set_person (&ico->organizer, value); + case CAL_COMPONENT_FIELD_DUE: + set_datetime (comp, value, cal_component_set_due); break; - case ICAL_OBJECT_FIELD_PERCENT: - /* FIXME: If set to 0 or 100 set other fields. */ - set_percent (&ico->percent, value); + case CAL_COMPONENT_FIELD_GEO: + set_geo (comp, value); break; - case ICAL_OBJECT_FIELD_PRIORITY: - set_priority (&ico->priority, value); + case CAL_COMPONENT_FIELD_PERCENT: + set_percent (comp, value); break; - case ICAL_OBJECT_FIELD_SUMMARY: - set_string (&ico->summary, value); + case CAL_COMPONENT_FIELD_PRIORITY: + set_priority (comp, value); break; - case ICAL_OBJECT_FIELD_URL: - set_string (&ico->url, value); + case CAL_COMPONENT_FIELD_SUMMARY: + set_summary (comp, value); break; - case ICAL_OBJECT_FIELD_COMPLETE: - /* FIXME: Need a ical_object_XXX function to mark an item - complete, which will also set the 'Completed' time and - maybe others such as the last modified fields. */ - ico->percent = 100; - ico->completed = time (NULL); - break; + /* FIXME: TRANSPARENCY requires an option menu cell renderer */ - case ICAL_OBJECT_FIELD_HAS_ALARMS: - case ICAL_OBJECT_FIELD_ICON: - case ICAL_OBJECT_FIELD_RECURRING: - case ICAL_OBJECT_FIELD_OVERDUE: - case ICAL_OBJECT_FIELD_COLOR: - /* These are all computed fields which can't be set, so we - do nothing. Note that the 'click-to-add' item will set all - fields when finished, so we don't want to output warnings - here. */ + case CAL_COMPONENT_FIELD_URL: + set_url (comp, value); break; default: @@ -1021,9 +1107,7 @@ calendar_model_set_value_at (ETableModel *etm, int col, int row, const void *val break; } - if (ico->new) - g_print ("Skipping update - new iCalObject\n"); - else if (!cal_client_update_object (priv->client, ico)) + if (!cal_client_update_object (priv->client, comp)) g_message ("calendar_model_set_value_at(): Could not update the object!"); } @@ -1037,26 +1121,30 @@ calendar_model_is_cell_editable (ETableModel *etm, int col, int row) model = CALENDAR_MODEL (etm); priv = model->priv; - g_return_val_if_fail (col >= 0 && col < ICAL_OBJECT_FIELD_NUM_FIELDS, FALSE); - /* We can't check this as 'click-to-add' passes row 0. */ + g_return_val_if_fail (col >= 0 && col < CAL_COMPONENT_FIELD_NUM_FIELDS, FALSE); + + /* FIXME: We can't check this as 'click-to-add' passes row 0. */ /*g_return_val_if_fail (row >= 0 && row < priv->objects->len, FALSE);*/ switch (col) { - case ICAL_OBJECT_FIELD_DTSTAMP: - case ICAL_OBJECT_FIELD_LAST_MOD: - case ICAL_OBJECT_FIELD_GEO: - case ICAL_OBJECT_FIELD_HAS_ALARMS: - case ICAL_OBJECT_FIELD_ICON: - case ICAL_OBJECT_FIELD_RECURRING: - case ICAL_OBJECT_FIELD_OVERDUE: - case ICAL_OBJECT_FIELD_COLOR: - return FALSE; + case CAL_COMPONENT_FIELD_CATEGORIES: + case CAL_COMPONENT_FIELD_COMPLETED: + case CAL_COMPONENT_FIELD_DTEND: + case CAL_COMPONENT_FIELD_DTSTART: + case CAL_COMPONENT_FIELD_DUE: + case CAL_COMPONENT_FIELD_GEO: + case CAL_COMPONENT_FIELD_PERCENT: + case CAL_COMPONENT_FIELD_PRIORITY: + case CAL_COMPONENT_FIELD_SUMMARY: + case CAL_COMPONENT_FIELD_URL: + return TRUE; default: - return TRUE; + return FALSE; } } +/* append_row handler for the calendar model */ static void calendar_model_append_row (ETableModel *etm, ETableModel *source, gint row) { |