From d757ccc2f3c0666a2d2033d81cc361ce5b68f5f7 Mon Sep 17 00:00:00 2001 From: Geert Janssens Date: Fri, 21 Jan 2011 11:51:40 +0000 Subject: [PATCH] This patch adds a new option under Edit -> Preferences -> Date/Time that looks like this: Date Completion When a date is entered without year, it should be taken: (*) In the current calendar year ( ) In a sliding 12-month window starting this many months before the current month: [ 6 ] Patch by Peter Selinger with minor modifications git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20132 57a11ea4-9604-0410-9ed3-97b8803252fd --- AUTHORS | 1 + src/core-utils/gnc-gconf-utils.h | 2 + src/gnome-utils/glade/preferences.glade | 97 ++++++++++++++---- src/gnome-utils/gnc-gnome-utils.c | 57 +++++++++++ .../schemas/apps_gnucash_general.schemas.in | 33 +++++++ src/libqof/qof/gnc-date.c | 99 ++++++++++++++++++- src/libqof/qof/gnc-date.h | 15 +++ 7 files changed, 279 insertions(+), 25 deletions(-) diff --git a/AUTHORS b/AUTHORS index 1fa42c7d76..85a8509081 100644 --- a/AUTHORS +++ b/AUTHORS @@ -250,6 +250,7 @@ Betina Schmidt German account template Dirk Schoenberger Qt/KDE work Jan Schrage documentation patches Christopher Seawood for XbaeMatrix core dump +Peter Selinger date completion Alessandro Seveso messages Italian translations Clytie Siddall Vietnamese translation Mike Simons misc configure.in patches diff --git a/src/core-utils/gnc-gconf-utils.h b/src/core-utils/gnc-gconf-utils.h index 48cc8fe8c9..f2a5a25fd1 100644 --- a/src/core-utils/gnc-gconf-utils.h +++ b/src/core-utils/gnc-gconf-utils.h @@ -66,6 +66,8 @@ #define KEY_NEGATIVE_IN_RED "negative_in_red" #define KEY_ENABLE_EURO "enable_euro" #define KEY_DATE_FORMAT "date_format" +#define KEY_DATE_COMPLETION "date_completion" +#define KEY_DATE_BACKMONTHS "date_backmonths" #define KEY_SHOW_LEAF_ACCOUNT_NAMES "show_leaf_account_names" typedef void (*GncGconfGeneralCb) (GConfEntry *entry, gpointer user_data); diff --git a/src/gnome-utils/glade/preferences.glade b/src/gnome-utils/glade/preferences.glade index 1edfb3cf73..bb6fbb0386 100644 --- a/src/gnome-utils/glade/preferences.glade +++ b/src/gnome-utils/glade/preferences.glade @@ -1088,34 +1088,91 @@ - - - - - - - - - - - - - - - - + + True + 0 + <b>Date Completion</b> + True + + + 12 + 13 + GTK_FILL + + - + + True + 0 + When a date is entered without year, it should be taken: + True + + + 4 + 13 + 14 + GTK_FILL + + - + + In the current calendar year + True + True + False + True + Dates will be completed so that they are within the current calendar year. + True + True + + + 2 + 14 + 15 + GTK_FILL + + 12 + - + + In a sliding 12-month window starting this +many months before the current month: + True + True + False + True + Dates will be completed so that they are close to the current date. Enter the maximum number of months to go backwards in time when completing dates. + True + True + gconf/general/date_completion/thisyear + + + 2 + 15 + 16 + GTK_FILL + + 12 + - + + True + True + Enter number of months. + + 6 0 11 1 4 0 + 1 + + + 16 + 17 + + + diff --git a/src/gnome-utils/gnc-gnome-utils.c b/src/gnome-utils/gnc-gnome-utils.c index 28b9a1e9d1..5eb8b7dc0b 100644 --- a/src/gnome-utils/gnc-gnome-utils.c +++ b/src/gnome-utils/gnc-gnome-utils.c @@ -118,6 +118,58 @@ gnc_configure_date_format (void) free(format_code); } +/* gnc_configure_date_completion + * sets dateCompletion to the current value on the scheme side. + * QOF_DATE_COMPLETION_THISYEAR: use current year + * QOF_DATE_COMPLETION_SLIDING: use a sliding 12-month window + * backmonths 0-11: windows starts this many months before current month + * + * Args: Nothing + * Returns: Nothing + */ +static void +gnc_configure_date_completion (void) +{ + char *date_completion = gnc_gconf_get_string(GCONF_GENERAL, + KEY_DATE_COMPLETION, NULL); + int backmonths = gnc_gconf_get_float(GCONF_GENERAL, + KEY_DATE_BACKMONTHS, NULL); + QofDateCompletion dc; + + if (backmonths < 0) + { + backmonths = 0; + } + else if (backmonths > 11) + { + backmonths = 11; + } + + if (date_completion && strcmp(date_completion, "sliding") == 0) + { + dc = QOF_DATE_COMPLETION_SLIDING; + } + else if (date_completion && strcmp(date_completion, "thisyear") == 0) + { + dc = QOF_DATE_COMPLETION_THISYEAR; + } + else + { + /* No preference has been set yet */ + PINFO("Incorrect date completion code, using defaults"); + dc = QOF_DATE_COMPLETION_THISYEAR; + backmonths = 6; + gnc_gconf_set_string (GCONF_GENERAL, KEY_DATE_COMPLETION, "thisyear", NULL); + gnc_gconf_set_float (GCONF_GENERAL, KEY_DATE_BACKMONTHS, 6.0, NULL); + } + qof_date_completion_set(dc, backmonths); + + if (date_completion != NULL) + { + free(date_completion); + } +} + char * gnc_gnome_locate_pixmap (const char *name) { @@ -628,9 +680,14 @@ gnc_gui_init(void) gnc_ui_util_init(); gnc_configure_date_format(); + gnc_configure_date_completion(); gnc_gconf_general_register_cb( KEY_DATE_FORMAT, (GncGconfGeneralCb)gnc_configure_date_format, NULL); + gnc_gconf_general_register_cb( + KEY_DATE_COMPLETION, (GncGconfGeneralCb)gnc_configure_date_completion, NULL); + gnc_gconf_general_register_cb( + KEY_DATE_BACKMONTHS, (GncGconfGeneralCb)gnc_configure_date_completion, NULL); gnc_gconf_general_register_any_cb( (GncGconfGeneralAnyCb)gnc_gui_refresh_all, NULL); diff --git a/src/gnome/schemas/apps_gnucash_general.schemas.in b/src/gnome/schemas/apps_gnucash_general.schemas.in index 444b938fd6..9ca20a00f9 100644 --- a/src/gnome/schemas/apps_gnucash_general.schemas.in +++ b/src/gnome/schemas/apps_gnucash_general.schemas.in @@ -301,6 +301,39 @@ + + /schemas/apps/gnucash/general/date_completion + /apps/gnucash/general/date_completion + gnucash + string + thisyear + + How to interpret dates without a year + + When a date is entered without year it can be completed so + that it will be within the current calendar year or close to + the current date based on a sliding window starting a set + number of months backwards in time. + + + + + + /schemas/apps/gnucash/general/date_backmonths + /apps/gnucash/general/date_backmonths + gnucash + float + 6.0 + + Maximum number of months to go back. + + Dates will be completed so that they are close to the current + date. Enter the maximum number of months to go backwards in + time when completing dates. + + + + /schemas/apps/gnucash/general/show_splash_screen /apps/gnucash/general/show_splash_screen diff --git a/src/libqof/qof/gnc-date.c b/src/libqof/qof/gnc-date.c index 523ce2e021..eaa979506d 100644 --- a/src/libqof/qof/gnc-date.c +++ b/src/libqof/qof/gnc-date.c @@ -85,6 +85,9 @@ const char *gnc_default_strftime_date_format = static QofDateFormat dateFormat = QOF_DATE_FORMAT_LOCALE; static QofDateFormat prevQofDateFormat = QOF_DATE_FORMAT_LOCALE; +static QofDateCompletion dateCompletion = QOF_DATE_COMPLETION_THISYEAR; +static int dateCompletionBackMonths = 6; + /* This static indicates the debugging module that this .o belongs to. */ static QofLogModule log_module = QOF_MOD_ENGINE; @@ -352,6 +355,48 @@ void qof_date_format_set(QofDateFormat df) return; } +/* set date completion method + +set dateCompletion to one of QOF_DATE_COMPLETION_THISYEAR (for +completing the year to the current calendar year) or +QOF_DATE_COMPLETION_SLIDING (for using a sliding 12-month window). The +sliding window starts 'backmonth' months before the current month (0-11). +checks to make sure it's a legal value + +param QofDateCompletion: indicates preferred completion method +param int: the number of months to go back in time (0-11) + +return void + +Globals: dateCompletion dateCompletionBackMonths +*/ +void qof_date_completion_set(QofDateCompletion dc, int backmonths) +{ + if (dc == QOF_DATE_COMPLETION_THISYEAR || + dc == QOF_DATE_COMPLETION_SLIDING) + { + dateCompletion = dc; + } + else + { + /* hack alert - Use a neutral default. */ + PERR("non-existent date completion set attempted. Setting current year completion as default"); + dateCompletion = QOF_DATE_COMPLETION_THISYEAR; + } + + if (backmonths < 0) + { + backmonths = 0; + } + else if (backmonths > 11) + { + backmonths = 11; + } + dateCompletionBackMonths = backmonths; + + return; +} + /* qof_date_format_get_string get the date format string for the current format @@ -599,6 +644,21 @@ qof_print_time_buff (char * buff, size_t len, time_t secs) /* ============================================================== */ +/* return the greatest integer <= a/b; works for b > 0 and positive or + negative a. */ +static int +floordiv(int a, int b) +{ + if (a >= 0) + { + return a / b; + } + else + { + return - ((-a-1) / b) - 1; + } +} + /* Convert a string into day, month and year integers Convert a string into day / month / year integers according to @@ -627,6 +687,7 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year, { char *dupe, *tmp, *first_field, *second_field, *third_field; int iday, imonth, iyear; + int now_day, now_month, now_year; struct tm *now, utc; time_t secs; @@ -669,12 +730,17 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year, } } - /* If any fields appear to be blank, use today's date */ + /* today's date */ time (&secs); now = localtime (&secs); - iday = now->tm_mday; - imonth = now->tm_mon + 1; - iyear = now->tm_year + 1900; + now_day = now->tm_mday; + now_month = now->tm_mon + 1; + now_year = now->tm_year + 1900; + + /* set defaults: if day or month appear to be blank, use today's date */ + iday = now_day; + imonth = now_month; + iyear = -1; /* get numeric values */ switch (which_format) @@ -812,10 +878,33 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year, } } + /* if no year was entered, choose a year according to the + dateCompletion preference. If it is + QOF_DATE_COMPLETION_THISYEAR, use the current year, else if it + is QOF_DATE_COMPLETION_SLIDING, use a sliding window that + starts dateCompletionBackMonths before the current month. + + We go by whole months, rather than days, because presumably + this is less confusing. + */ + + if (iyear == -1) + { + if (dateCompletion == QOF_DATE_COMPLETION_THISYEAR) + { + iyear = now_year; /* use the current year */ + } + else + { + iyear = now_year - floordiv(imonth - now_month + + dateCompletionBackMonths, 12); + } + } + /* 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) - iyear += ((int) ((now->tm_year + 1950 - iyear) / 100)) * 100; + iyear += ((int) ((now_year + 50 - iyear) / 100)) * 100; if (year) *year = iyear; if (month) *month = imonth; diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h index 17bcd1bbd6..c9665ffa73 100644 --- a/src/libqof/qof/gnc-date.h +++ b/src/libqof/qof/gnc-date.h @@ -110,6 +110,13 @@ typedef enum #define DATE_FORMAT_FIRST QOF_DATE_FORMAT_US #define DATE_FORMAT_LAST QOF_DATE_FORMAT_LOCALE +/** Enum for date completion modes (for dates entered without year) */ +typedef enum +{ + QOF_DATE_COMPLETION_THISYEAR, /**< use current year */ + QOF_DATE_COMPLETION_SLIDING, /**< use sliding 12-month window */ +} QofDateCompletion; + /** \deprecated qof_date_format_get_format has been replaced by qof_date_text_format_get_string */ #define qof_date_format_get_format qof_date_text_format_get_string @@ -326,6 +333,14 @@ const gchar *qof_date_format_get_string(QofDateFormat df); const gchar *qof_date_text_format_get_string(QofDateFormat df); // @} +/** + * The qof_date_completion_set() routing sets the date completion method to + * one of QOF_DATE_COMPLETION_THISYEAR (for completing the year to + * the current calendar year) or QOF_DATE_COMPLETION_SLIDING (for + * using a sliding 12-month window). The sliding window starts + * 'backmonth' months before the current month (0-11) */ +void qof_date_completion_set(QofDateCompletion dc, int backmonths); + /** dateSeparator * Return the field separator for the current date format *