From b820a5006c9da81d8822626be1fc115cb1d9ada3 Mon Sep 17 00:00:00 2001 From: David Hampton Date: Sat, 27 Apr 2002 21:43:25 +0000 Subject: [PATCH] Default date format to the users locale. Date widgets now accept a single number as the day, or two numbers as day and month (ordered according to the users date preference). git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6822 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 24 ++++ src/app-utils/prefs.scm | 2 +- src/engine/date.c | 115 ++++++++++++++++--- src/gnome-utils/gnc-date-edit.c | 38 ++++++ src/gnome-utils/gnc-date-edit.h | 3 + src/gnome/top-level.c | 2 +- src/gnome/window-reconcile.c | 1 + src/register/register-gnome/datecell-gnome.c | 5 + 8 files changed, 169 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09dba722d3..10ec9fb435 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2002-04-27 David Hampton + + * src/app-utils/prefs.scm: + * src/engine/date.c: + * src/gnome/top-level.c (gnc_configure_date_format): Change the + default date format to be the user's LOCALE setting. + + * src/engine/date.c (scanDate): Totally work over this routine to + support a user entering one, two, or three numbers. If one, assume + day. If two assume day/month, ordering from locale. Three is + day/month/year, ordering from locale. Also protect against an old + date string being supplied to the routine after the date format + has been changed. + + * src/register/register-gnome/datecell-gnome.c + (gnc_date_cell_leave): Reprint the time when leaving a date_cell + field. + + * src/gnome-utils/gnc-date-edit.c (date_focus_out_event): New + routine to reprint the time when tabbing out of a date_entry cell. + (create_children): Tie in new routine. + (gnc_date_editable_enters): New helper routine for setting + gnome_dialog_editable_enters on a date_entry widget. + 2002-04-23 David Hampton * src/app-utils/gnc-component-manager.h: Change diff --git a/src/app-utils/prefs.scm b/src/app-utils/prefs.scm index 3719a6ff90..4355301ba9 100644 --- a/src/app-utils/prefs.scm +++ b/src/app-utils/prefs.scm @@ -141,7 +141,7 @@ (gnc:register-configuration-option (gnc:make-multichoice-option (N_ "International") (N_ "Date Format") - "a" (N_ "Date Format Display") 'us + "a" (N_ "Date Format Display") 'locale (list (list->vector (list 'us (N_ "US") (N_ "US-style: mm/dd/yyyy"))) diff --git a/src/engine/date.c b/src/engine/date.c index e7e0ae5751..b480eeb154 100644 --- a/src/engine/date.c +++ b/src/engine/date.c @@ -55,7 +55,8 @@ #endif /* This is now user configured through the gnome options system() */ -static DateFormat dateFormat = DATE_FORMAT_US; +static DateFormat dateFormat = DATE_FORMAT_LOCALE; +static DateFormat prevDateFormat = DATE_FORMAT_LOCALE; /* This static indicates the debugging module that this .o belongs to. */ static short module = MOD_ENGINE; @@ -176,6 +177,7 @@ void setDateFormat(DateFormat df) { if(df >= DATE_FORMAT_FIRST && df <= DATE_FORMAT_LAST) { + prevDateFormat = dateFormat; dateFormat = df; } else @@ -289,6 +291,12 @@ gnc_print_date (Timespec ts) * Convert a string into day / month / year integers according to * the current dateFormat value. * + * This function will always parse a single number as the day of + * the month, regardless of the ordering of the dateFormat value. + * Two numbers will always be parsed as the day and the month, in + * the same order that they appear in the dateFormat value. Three + * numbers are parsed exactly as specified in the dateFormat field. + * * Args: buff - pointer to date string * day - will store day of the month as 1 ... 31 * month - will store month of the year as 1 ... 12 @@ -298,15 +306,16 @@ gnc_print_date (Timespec ts) * * Globals: global dateFormat value */ -void -scanDate (const char *buff, int *day, int *month, int *year) +static gboolean +scanDateInternal (const char *buff, int *day, int *month, int *year, + DateFormat which_format) { char *dupe, *tmp, *first_field, *second_field, *third_field; int iday, imonth, iyear; struct tm *now; time_t secs; - if (!buff) return; + if (!buff) return(FALSE); dupe = g_strdup (buff); @@ -334,41 +343,102 @@ scanDate (const char *buff, int *day, int *month, int *year) iyear = now->tm_year+1900; /* get numeric values */ - switch (dateFormat) + switch (which_format) { case DATE_FORMAT_LOCALE: if (buff[0] != '\0') { struct tm thetime; + /* Parse time string. */ + memset(&thetime, -1, sizeof(struct tm)); strptime (buff, GNC_D_FMT, &thetime); - iday = thetime.tm_mday; - imonth = thetime.tm_mon + 1; - iyear = thetime.tm_year + 1900; + if (third_field) { + /* Easy. All three values were parsed. */ + iyear = thetime.tm_year + 1900; + iday = thetime.tm_mday; + imonth = thetime.tm_mon + 1; + } else if (second_field) { + /* Hard. Two values parsed. Figure out the ordering. */ + if (thetime.tm_year == -1) { + /* %m-%d or %d-%m. Don't care. Already parsed correctly. */ + iday = thetime.tm_mday; + imonth = thetime.tm_mon + 1; + } else if (thetime.tm_mon != -1) { + /* Must be %Y-%m-%d. Reparse as %m-%d.*/ + imonth = atoi(first_field); + iday = atoi(second_field); + } else { + /* Must be %Y-%d-%m. Reparse as %d-%m. */ + iday = atoi(first_field); + imonth = atoi(second_field); + } + } else if (first_field) { + iday = atoi(first_field); + } } break; case DATE_FORMAT_UK: case DATE_FORMAT_CE: - if (first_field) iday = atoi (first_field); - if (second_field) imonth = atoi (second_field); - if (third_field) iyear = atoi (third_field); + if (third_field) { + iday = atoi(first_field); + imonth = atoi(second_field); + iyear = atoi(third_field); + } else if (second_field) { + iday = atoi(first_field); + imonth = atoi(second_field); + } else if (first_field) { + iday = atoi(first_field); + } break; case DATE_FORMAT_ISO: - if (first_field) iyear = atoi (first_field); - if (second_field) imonth = atoi (second_field); - if (third_field) iday = atoi (third_field); + if (third_field) { + iyear = atoi(first_field); + imonth = atoi(second_field); + iday = atoi(third_field); + } else if (second_field) { + imonth = atoi(first_field); + iday = atoi(second_field); + } else if (first_field) { + iday = atoi(first_field); + } break; - case DATE_FORMAT_US: - default: - if (first_field) imonth = atoi (first_field); - if (second_field) iday = atoi (second_field); - if (third_field) iyear = atoi (third_field); + case DATE_FORMAT_US: + default: + if (third_field) { + imonth = atoi(first_field); + iday = atoi(second_field); + iyear = atoi(third_field); + } else if (second_field) { + imonth = atoi(first_field); + iday = atoi(second_field); + } else if (first_field) { + iday = atoi(first_field); + } break; } g_free (dupe); + if (imonth > 12 || iday > 31) { + /* + * Ack! Thppfft! Someone just fed this routine a string in the + * wrong date format. This is known to happen if a register + * window is open when changing the date format. Try the + * previous date format. If that doesn't work, bail and give the + * caller what they asked for (garbage) parsed in the new format. + * + * Note: This test cannot detect any format change that only + * swaps month and day field, if the day is 12 or less. This is + * deemed acceptable given the obscurity of this bug. + */ + if (which_format == prevDateFormat) + return(FALSE); + if (scanDateInternal(buff, day, month, year, prevDateFormat)) + return(TRUE); + } + /* if the year entered is smaller than 100, assume we mean the current century (and are not revising some roman emperor's books) */ if (iyear < 100) @@ -377,6 +447,13 @@ scanDate (const char *buff, int *day, int *month, int *year) if (year) *year=iyear; if (month) *month=imonth; if (day) *day=iday; + return(TRUE); +} + +void +scanDate (const char *buff, int *day, int *month, int *year) +{ + scanDateInternal(buff, day, month, year, dateFormat); } /** diff --git a/src/gnome-utils/gnc-date-edit.c b/src/gnome-utils/gnc-date-edit.c index 958227cb41..7ab13cefcd 100644 --- a/src/gnome-utils/gnc-date-edit.c +++ b/src/gnome-utils/gnc-date-edit.c @@ -572,6 +572,22 @@ date_accel_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) return TRUE; } +static int +date_focus_out_event(GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + GNCDateEdit *gde = data; + struct tm tm; + + tm = gnc_date_edit_get_date_internal (gde); + gnc_date_edit_set_time (gde, mktime (&tm)); + + gtk_calendar_select_month (GTK_CALENDAR (gde->calendar), tm.tm_mon, + 1900 + tm.tm_year); + gtk_calendar_select_day (GTK_CALENDAR (gde->calendar), tm.tm_mday); + + return TRUE; +} + static void create_children (GNCDateEdit *gde) { @@ -585,6 +601,8 @@ create_children (GNCDateEdit *gde) gtk_widget_show (gde->date_entry); gtk_signal_connect (GTK_OBJECT (gde->date_entry), "key_press_event", GTK_SIGNAL_FUNC(date_accel_key_press), gde); + gtk_signal_connect (GTK_OBJECT (gde->date_entry), "focus_out_event", + GTK_SIGNAL_FUNC(date_focus_out_event), gde); gde->date_button = gtk_button_new (); gtk_signal_connect (GTK_OBJECT (gde->date_button), "clicked", @@ -930,6 +948,26 @@ gnc_date_edit_get_flags (GNCDateEdit *gde) return gde->flags; } +/** + * gnc_date_editable_enters: + * @dialog: The gnome dialog this date editor lives in + * @gde: The date editor to modity + * + * Extracts the editable field from a GNCDateEdit widget, and sets it + * up so that pressing the Enter key in this field as the same as + * clicking the button that has the default. + **/ +void +gnc_date_editable_enters (GnomeDialog *dialog, GNCDateEdit *gde) +{ + if (!dialog || !gde) + return; + + gnome_dialog_editable_enters(GNOME_DIALOG(dialog), + GTK_EDITABLE(gde->date_entry)); +} + + /* Local Variables: c-basic-offset: 8 diff --git a/src/gnome-utils/gnc-date-edit.h b/src/gnome-utils/gnc-date-edit.h index 22ea5f8d53..8aab6884e3 100644 --- a/src/gnome-utils/gnc-date-edit.h +++ b/src/gnome-utils/gnc-date-edit.h @@ -108,6 +108,9 @@ void gnc_date_edit_set_flags (GNCDateEdit *gde, GNCDateEditFlags flags); int gnc_date_edit_get_flags (GNCDateEdit *gde); +void gnc_date_editable_enters (GnomeDialog *dialog, + GNCDateEdit *gde); + END_GNOME_DECLS diff --git a/src/gnome/top-level.c b/src/gnome/top-level.c index 2281b05ea8..1058201c9c 100644 --- a/src/gnome/top-level.c +++ b/src/gnome/top-level.c @@ -485,7 +485,7 @@ gnc_configure_date_format (void) { char *format_code = gnc_lookup_multichoice_option("International", "Date Format", - "us"); + "locale"); DateFormat df; diff --git a/src/gnome/window-reconcile.c b/src/gnome/window-reconcile.c index 45b5afe9b5..e74e54b1a1 100644 --- a/src/gnome/window-reconcile.c +++ b/src/gnome/window-reconcile.c @@ -637,6 +637,7 @@ startRecnWindow(GtkWidget *parent, Account *account, /* need to get a callback on date changes to update the recn balance */ gtk_signal_connect ( GTK_OBJECT (date_value), "date_changed", GTK_SIGNAL_FUNC (gnc_start_recn_date_changed), (gpointer) &data ); + gnc_date_editable_enters(GNOME_DIALOG(dialog), GNC_DATE_EDIT(date_value)); print_info.use_symbol = 0; gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (end_value), print_info); diff --git a/src/register/register-gnome/datecell-gnome.c b/src/register/register-gnome/datecell-gnome.c index 558534cad4..acf56db7dd 100644 --- a/src/register/register-gnome/datecell-gnome.c +++ b/src/register/register-gnome/datecell-gnome.c @@ -637,6 +637,7 @@ gnc_date_cell_enter (BasicCell *bcell, static void gnc_date_cell_leave (BasicCell *bcell) { + Timespec ts; PopBox *box = bcell->gui_private; date_picker_disconnect_signals ((DateCell *) bcell); @@ -645,6 +646,10 @@ gnc_date_cell_leave (BasicCell *bcell) NULL, NULL, NULL, NULL, NULL); box->calendar_popped = FALSE; + + /* Refresh the date to expand any shortcuts. */ + gnc_date_cell_get_date ((DateCell *)bcell, &ts); + gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec); } void