From 449df116d8abe6c1ad6e76bb54e54c669593bf5e Mon Sep 17 00:00:00 2001 From: Christian Stimming Date: Thu, 6 May 2010 09:01:46 +0000 Subject: [PATCH] Bug #612212: Provide a method to set the default budget Patch by Jeff Kletsky. (Cstim: Accepted even though string freeze is in effect because it was submitted before the freeze. Also, the string additions are very minor.) Summary of Changes: * Initial story related to providing default budget control * Add a "Budgeting" tab to the book-level preferences dialog * Add a "Default Budget" selector to the "Budgeting" tab * Modify gnc_budget_get_default() to * Respect the new KVP, if present * Fall back to 2.2.x behavior, if not present * Modify gnc:make-budget-option * Reformatted for readability with additional comments * Default is now "#f" so that selected value is always saved Otherwise, if selection happened to be the current default and the default was later changed, the report would change * getter, setter, and generate-restore-form all now consistent * setter now always takes a budget object * generate-restore-form does not rely on "hack" in setter that previously allowed either a budget object or a GUID string This is a different fix for 603215 -- see Known Issues * Provide translation support for "Trading Acccounts" (and "Budgeting") * Refactor #define names for consistency and extensibility * KVP_OPTION_PATH for consistency with Guile usage * OPTION_SECTION_blahblah * OPTION_NAME_blahblah * Modify qofbookslots.h to be "SWIG-aware" * Pick up qofbookslots.h in make-gnucash-potfiles.in and po/POTFILES.in Known Issues: * There is no selection (yet) for "Use default budget" so changing the default budget and reloading a report does not change the budget used * setter is no more robust to "bad" values than in previous code * Budget reports created with 2.3.x after r18528 (between 2.3.8 and 2.3.9) may not load or re-render as they relied on the setter taking either a budget object or a GUID as a string This should not impact any 2.2.x users as nothing was saved under 2.2.x related to the default budget. This can be resolved through removing the option restore code in ~/.gnucash/saved-reports-2.4 and, if affected reports were open, in ~/.gnucash/books/ * Budget reports prior to r18528 did not save budget selection (603215) git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@19123 57a11ea4-9604-0410-9ed3-97b8803252fd --- make-gnucash-potfiles.in | 1 + po/POTFILES.in | 1 + src/app-utils/app-utils.scm | 2 +- src/app-utils/options.scm | 110 ++++++++++++------ .../business-utils/business-prefs.scm | 13 ++- .../business-utils/business-utils.scm | 11 +- src/engine/engine.i | 10 +- src/engine/gnc-budget.c | 34 +++++- src/libqof/qof/qofbook.c | 8 +- src/libqof/qof/qofbookslots.h | 52 ++++++++- 10 files changed, 189 insertions(+), 53 deletions(-) diff --git a/make-gnucash-potfiles.in b/make-gnucash-potfiles.in index ef266a32c9..7f9818479b 100644 --- a/make-gnucash-potfiles.in +++ b/make-gnucash-potfiles.in @@ -52,5 +52,6 @@ foreach my $file (@possible_files) { # These are also added, even though they are outside of src/ print "src/gnome/gnucash.desktop.in.in\n"; print "src/libqof/qof/gnc-date.c\n"; +print "src/libqof/qof/qofbookslots.h\n"; print "intl-scm/guile-strings.c\n"; print "doc/tip_of_the_day.list.in\n"; diff --git a/po/POTFILES.in b/po/POTFILES.in index 6a673f627f..7898a6598f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -521,5 +521,6 @@ src/tax/us/gncmod-tax-us.c src/gnome/gnucash.desktop.in.in src/libqof/backend/file/qsf-backend.c src/libqof/qof/gnc-date.c +src/libqof/qof/qofbookslots.h intl-scm/guile-strings.c doc/tip_of_the_day.list.in diff --git a/src/app-utils/app-utils.scm b/src/app-utils/app-utils.scm index 7126f9626d..5a2f924a1d 100644 --- a/src/app-utils/app-utils.scm +++ b/src/app-utils/app-utils.scm @@ -257,7 +257,7 @@ (export simple-obj-from-list) (export make-simple-obj) -(define gnc:*kvp-option-path* (list BOOK-OPTIONS-NAME)) +(define gnc:*kvp-option-path* (list KVP-OPTION-PATH)) (export gnc:*kvp-option-path*) (load-from-path "c-interface.scm") diff --git a/src/app-utils/options.scm b/src/app-utils/options.scm index 7795a3f83b..78737cce1e 100644 --- a/src/app-utils/options.scm +++ b/src/app-utils/options.scm @@ -304,51 +304,95 @@ #f #f #f #f))) ;; budget option -;; TODO: need to double-check this proc +;; TODO: need to double-check this proc (dates back to r11545 or eariler) +;; +;; Always takes/returns a budget +;; Stores the GUID in the KVP +;; (define (gnc:make-budget-option section name sort-tag documentation-string) - (define (budget->guid budget) - (cond ((eq? budget #f) #f) - ((string? budget) budget) - (else (gncBudgetGetGUID budget)))) - - (define (guid->budget budget) - (if (string? budget) - (gnc-budget-lookup budget (gnc-get-current-book)) - budget)) - - (let* ((default-value (gnc-budget-get-default (gnc-get-current-book))) - (value (budget->guid default-value)) - (option-set #f) - (value->string (lambda () - (string-append "'" (gnc:value->string value)))) + (let* ((initial-budget (gnc-budget-get-default (gnc-get-current-book))) + (selection-budget initial-budget) ) - (gnc:make-option - section name sort-tag 'budget documentation-string - ;; the getter should always return a budget pointer - (lambda () (guid->budget ;; getter - (if option-set - value - default-value)) - ) - (lambda (x) (set! value (budget->guid x)) - (set! option-set #t)) ;; setter + (gnc:make-option + section + name + sort-tag + 'budget + documentation-string + + ;; getter -- Return a budget pointer + (lambda () + selection-budget) + + ;; setter -- takes a budget + (lambda (x) + (set! selection-budget x)) + + ;; default-getter + ;; Default now is #f so saving is independent of book-level default (lambda () - (guid->budget - (gnc-budget-get-default (gnc-get-current-book)))) ;; default-getter - (gnc:restore-form-generator value->string) ;; ?? - (lambda (f p) (kvp-frame-set-slot-path-gslist f value p)) + #f) + + ;; generate-restore-form + ;; "return 'ascii represention of a function' + ;; that will set the option passed as its lone parameter + ;; to the value it was when the picker was first displayed" + ;; + ;; *This* is used to restore reports, not the KVP -- and is stored as text + ;; This does not run in closure with direct access to the option's + ;; internal variables, so the setter generally gets used + (lambda () + (string-append + "(lambda (option) " + "(if option ((gnc:option-setter option) " + "(gnc-budget-lookup " + (gnc:value->string (gncBudgetGetGUID selection-budget)) + " (gnc-get-current-book)))))")) + + ;; scm->kvp -- commit the change + ;; f -- kvp-frame; p -- key-path + (lambda (f p) + (kvp-frame-set-slot-path-gslist + f (gncBudgetGetGUID selection-budget) p)) + + ;; kvp->scm -- get the stored value (lambda (f p) (let ((v (kvp-frame-get-slot-path-gslist f p))) (if (and v (string? v)) - (set! value v)))) - (lambda (x) (list #t x)) ;; value-validator - #f #f #f #f))) + (begin + (set! selection-budget (gnc-budget-lookup v (gnc-get-current-book))))))) + + ;; value-validator -- returns (#t value) or (#f "failure message") + ;; As no user-generated input, this legacy hard-wire is probably ok + (lambda (x) + (list #t x)) + + ;; option-data + #f + + ;; option-data-fns -- used for multi-pick (this isn't one), or #f + ;; Vector of five functions + ;; 1) () => number of choices + ;; 2) (n) => key for the nth choice + ;; 3) (n) => string for the nth choice + ;; 4) (n) => description for the nth choice + ;; 5) (key) => n (assuming this is the reverse key lookup) + #f + + ;; strings-getter -- list of all translatable strings in the option + #f + + ;; options-widget-changed-proc -- callback for what it sounds like + #f + + ))) ;; completes gnc:make-budget-option + ;; commodity options use a specialized widget for entering commodities ;; in the GUI implementation. diff --git a/src/business/business-utils/business-prefs.scm b/src/business/business-utils/business-prefs.scm index e97e8d00ef..2819800dc8 100644 --- a/src/business/business-utils/business-prefs.scm +++ b/src/business/business-utils/business-prefs.scm @@ -84,9 +84,18 @@ (reg-option (gnc:make-simple-boolean-option - gnc:*book-label* gnc:*trading-accounts* - "a" (N_ "True if trading accounts should be used for transactions involving more than one commodity") + gnc:*option-section-accounts* gnc:*option-name-trading-accounts* + "a" (N_ "Check to have trading accounts used for transactions involving more than one currency or commodity") #f)) + + ;; Budgeting Tab + + (reg-option + (gnc:make-budget-option + gnc:*option-section-budgeting* gnc:*option-name-default-budget* + "a" (N_ "Budget to be used when none has been otherwise specified"))) + ) + (gnc-register-kvp-option-generator QOF-ID-BOOK-SCM book-options-generator) diff --git a/src/business/business-utils/business-utils.scm b/src/business/business-utils/business-utils.scm index 9263e45f7f..8cf88ec7ff 100644 --- a/src/business/business-utils/business-utils.scm +++ b/src/business/business-utils/business-utils.scm @@ -18,10 +18,15 @@ gnc:*company-phone* gnc:*company-fax* gnc:*company-url* gnc:*company-email* gnc:*company-contact*) -(define gnc:*book-label* ACCOUNT-OPTIONS-SECTION) -(define gnc:*trading-accounts* TRADING-ACCOUNTS-OPTION) +(define gnc:*option-section-accounts* OPTION-SECTION-ACCOUNTS) +(define gnc:*option-name-trading-accounts* OPTION-NAME-TRADING-ACCOUNTS) -(export gnc:*book-label* gnc:*trading-accounts*) +(export gnc:*option-section-accounts* gnc:*option-name-trading-accounts*) + +(define gnc:*option-section-budgeting* OPTION-SECTION-BUDGETING) +(define gnc:*option-name-default-budget* OPTION-NAME-DEFAULT-BUDGET) + +(export gnc:*option-section-budgeting* gnc:*option-name-default-budget*) (load-from-path "business-options.scm") (load-from-path "business-prefs.scm") diff --git a/src/engine/engine.i b/src/engine/engine.i index 9b94b2d094..f13650664e 100644 --- a/src/engine/engine.i +++ b/src/engine/engine.i @@ -297,9 +297,13 @@ KvpValue * kvp_frame_get_slot_path_gslist (KvpFrame *frame, GSList *key_path); SET_ENUM("TRANS-DESCRIPTION"); SET_ENUM("TRANS-NUM"); - SET_ENUM("BOOK-OPTIONS-NAME"); - SET_ENUM("ACCOUNT-OPTIONS-SECTION"); - SET_ENUM("TRADING-ACCOUNTS-OPTION"); + SET_ENUM("KVP-OPTION-PATH"); + + SET_ENUM("OPTION-SECTION-ACCOUNTS"); + SET_ENUM("OPTION-NAME-TRADING-ACCOUNTS"); + + SET_ENUM("OPTION-SECTION-BUDGETING"); + SET_ENUM("OPTION-NAME-DEFAULT-BUDGET"); SET_ENUM("ACCOUNT-CODE-"); /* sic */ diff --git a/src/engine/gnc-budget.c b/src/engine/gnc-budget.c index fb788f073a..c3408bf22d 100644 --- a/src/engine/gnc-budget.c +++ b/src/engine/gnc-budget.c @@ -28,6 +28,7 @@ #include #include #include "qof.h" +#include "qofbookslots.h" #include "Account.h" @@ -596,13 +597,38 @@ gnc_budget_get_default (QofBook *book) { QofCollection *col; GncBudget *bgt = NULL; + kvp_value *kvp_default_budget; + const GncGUID *default_budget_guid; g_return_val_if_fail(book, NULL); - col = qof_book_get_collection(book, GNC_ID_BUDGET); - if (qof_collection_count(col) > 0) - { - qof_collection_foreach(col, just_get_one, &bgt); + + /* See if there is a budget selected in the KVP perferences */ + + kvp_default_budget = kvp_frame_get_slot_path(qof_book_get_slots (book), + KVP_OPTION_PATH, + OPTION_SECTION_BUDGETING, + OPTION_NAME_DEFAULT_BUDGET, + NULL); + + if (kvp_default_budget != NULL ) { + default_budget_guid = kvp_value_get_guid(kvp_default_budget); + if (default_budget_guid != NULL) { + col = qof_book_get_collection(book, GNC_ID_BUDGET); + bgt = (GncBudget *) qof_collection_lookup_entity(col, + default_budget_guid); + } } + + /* Revert to 2.2.x behavior if there is no defined budget in KVP */ + + if ( bgt == NULL ) { + col = qof_book_get_collection(book, GNC_ID_BUDGET); + if (qof_collection_count(col) > 0) + { + qof_collection_foreach(col, just_get_one, &bgt); + } + } + return bgt; } diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c index e72de76374..2160faa1b9 100644 --- a/src/libqof/qof/qofbook.c +++ b/src/libqof/qof/qofbook.c @@ -457,11 +457,11 @@ qof_book_use_trading_accounts (const QofBook *book) const char *opt; kvp_value *kvp_val; - kvp_val = kvp_frame_get_slot_path (qof_book_get_slots (book), - BOOK_OPTIONS_NAME, - ACCOUNT_OPTIONS_SECTION, - TRADING_ACCOUNTS_OPTION, NULL); + KVP_OPTION_PATH, + OPTION_SECTION_ACCOUNTS, + OPTION_NAME_TRADING_ACCOUNTS, + NULL); if (kvp_val == NULL) return FALSE; diff --git a/src/libqof/qof/qofbookslots.h b/src/libqof/qof/qofbookslots.h index 54bae92758..448309549f 100644 --- a/src/libqof/qof/qofbookslots.h +++ b/src/libqof/qof/qofbookslots.h @@ -19,6 +19,12 @@ * * \********************************************************************/ +#ifndef SWIG /* swig doesn't see N_() as a string constant */ +#include +#else +#define N_(string) string +#endif + /** @name Book parameter names * These define the names used for the slots used to store book level parameters. @@ -26,8 +32,48 @@ * Scheme code too. @{ */ -#define BOOK_OPTIONS_NAME "options" -#define ACCOUNT_OPTIONS_SECTION "Accounts" -#define TRADING_ACCOUNTS_OPTION "Trading Accounts" + + +/* + * See also SET_ENUM() in src/engine/engine.i + * + * SOME_DEFINED_NAME gets mapped into SOME-DEFINED-NAME by SWIG + * http://www.swig.org/Doc1.3/Guile.html#Guile_nn10 + */ + + +/* + * gnc:*kvp-option-path* is used to refer to the kvp frame + * in which book-level options are stored. + * It is tied from this C #define in + * src/app-utils/app-utils.scm + * and is extensively used in + * src/app-utils/option-util.c + * src/gnome-utils/gnome-utils.scm + * various reports + */ + +#define KVP_OPTION_PATH "options" + +/* + * Various option sections and options within those sections + * The untranslated string is used for the key in the KVP + * The translated string appears as the tab name and as the + * text associated with the option selector on the tab + */ + +#define OPTION_SECTION_ACCOUNTS N_("Accounts") +#define OPTION_NAME_TRADING_ACCOUNTS N_("Use Trading Accounts") + +#define OPTION_SECTION_BUDGETING N_("Budgeting") +#define OPTION_NAME_DEFAULT_BUDGET N_("Default Budget") /** @} */ + +/* For the grep-happy: + * KVP-OPTION-PATH + * OPTION-SECTION-ACCOUNTS + * OPTION-NAME-TRADING-ACCOUNTS + * OPTION-SECTION-BUDGETING + * OPTION-NAME-DEFAULT-BUDGET + */