mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-12-01 13:09:41 -06:00
2040 lines
75 KiB
Scheme
2040 lines
75 KiB
Scheme
;; Scheme code for supporting options
|
|
;;
|
|
;; This program is free software; you can redistribute it and/or
|
|
;; modify it under the terms of the GNU General Public License as
|
|
;; published by the Free Software Foundation; either version 2 of
|
|
;; the License, or (at your option) any later version.
|
|
;;
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; if not, contact:
|
|
;;
|
|
;; Free Software Foundation Voice: +1-617-542-5942
|
|
;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
|
|
;; Boston, MA 02110-1301, USA gnu@gnu.org
|
|
(use-modules (ice-9 regex))
|
|
(use-modules (gnucash core-utils))
|
|
|
|
(define (rpterror-earlier type newoption fallback)
|
|
;; Translators: the 3 ~a below refer to (1) option type (2) unknown
|
|
;; new option name, (3) fallback option name. The order is
|
|
;; important, and must not be changed.
|
|
(let* ((template (N_ "This report was saved using a later version of \
|
|
GnuCash. One of the newer ~a options '~a' is not available, fallback to \
|
|
the option '~a'."))
|
|
(console-msg (format #f template type newoption fallback))
|
|
(ui-msg (format #f (G_ template) type newoption fallback)))
|
|
(gnc:gui-warn console-msg ui-msg)))
|
|
|
|
(define (gnc:make-option
|
|
;; The category of this option
|
|
section
|
|
name
|
|
;; The sort-tag determines the relative ordering of options in
|
|
;; this category. It is used by the gui for display.
|
|
sort-tag
|
|
type
|
|
documentation-string
|
|
getter
|
|
;; The setter is responsible for ensuring that the value is valid.
|
|
setter
|
|
default-getter
|
|
;; Restore form generator should generate an ascii representation
|
|
;; of a function taking one argument. The argument will be an
|
|
;; option. The function should restore the option to the original
|
|
;; value.
|
|
generate-restore-form
|
|
;; the scm->kvp and kvp->scm functions should save and load
|
|
;; the option to the book. The arguments to these function will be
|
|
;; a book and a base key-path list for this option.
|
|
scm->kvp
|
|
kvp->scm
|
|
;; Validation func should accept a value and return (#t value)
|
|
;; on success, and (#f "failure-message") on failure. If #t,
|
|
;; the supplied value will be used by the gui to set the option.
|
|
value-validator
|
|
;;; free-form storage depending on type.
|
|
option-data
|
|
;; If this is a "multiple choice" type of option,
|
|
;; this should be a vector of the following five functions:
|
|
;;
|
|
;; Function 1: taking no arguments, giving the number of choices
|
|
;;
|
|
;; Function 2: taking one argument, a non-negative integer, that
|
|
;; returns the scheme value (usually a symbol) matching the
|
|
;; nth choice
|
|
;;
|
|
;; Function 3: taking one argument, a non-negative integer,
|
|
;; that returns the string matching the nth choice
|
|
;;
|
|
;; Function 4: takes one argument and returns the description
|
|
;; containing the nth choice
|
|
;;
|
|
;; Function 5: giving a possible value and returning the index
|
|
;; if an option doesn't use these, this should just be a #f
|
|
option-data-fns
|
|
;; This function should return a list of all the strings
|
|
;; in the option other than the section, name, (define
|
|
;; (list-lookup list item) and documentation-string that
|
|
;; might be displayed to the user (and thus should be
|
|
;; translated).
|
|
strings-getter
|
|
;; This function will be called when the GUI representation
|
|
;; of the option is changed. This will normally occur before
|
|
;; the setter is called, because setters are only called when
|
|
;; the user selects "OK" or "Apply". Therefore, this
|
|
;; callback shouldn't be used to make changes to the actual
|
|
;; options database.
|
|
option-widget-changed-proc)
|
|
(let ((changed-callback #f))
|
|
(vector section
|
|
name
|
|
sort-tag
|
|
type
|
|
documentation-string
|
|
getter
|
|
(lambda args
|
|
(apply setter args)
|
|
(if changed-callback (changed-callback)))
|
|
default-getter
|
|
generate-restore-form
|
|
scm->kvp
|
|
kvp->scm
|
|
value-validator
|
|
option-data
|
|
option-data-fns
|
|
(lambda (callback) (set! changed-callback callback))
|
|
strings-getter
|
|
option-widget-changed-proc)))
|
|
|
|
(define (gnc:option-section option)
|
|
(vector-ref option 0))
|
|
(define (gnc:option-name option)
|
|
(vector-ref option 1))
|
|
(define (gnc:option-sort-tag option)
|
|
(vector-ref option 2))
|
|
(define (gnc:option-type option)
|
|
(vector-ref option 3))
|
|
(define (gnc:option-documentation option)
|
|
(vector-ref option 4))
|
|
(define (gnc:option-getter option)
|
|
(vector-ref option 5))
|
|
(define (gnc:option-setter option)
|
|
(vector-ref option 6))
|
|
(define (gnc:option-default-getter option)
|
|
(vector-ref option 7))
|
|
(define (gnc:option-generate-restore-form option)
|
|
(vector-ref option 8))
|
|
(define (gnc:option-scm->kvp option)
|
|
(vector-ref option 9))
|
|
(define (gnc:set-option-scm->kvp option v)
|
|
(vector-set! option 9 v))
|
|
(define (gnc:option-kvp->scm option)
|
|
(vector-ref option 10))
|
|
(define (gnc:set-option-kvp->scm option v)
|
|
(vector-set! option 10 v))
|
|
(define (gnc:option-value-validator option)
|
|
(vector-ref option 11))
|
|
(define (gnc:option-data option)
|
|
(vector-ref option 12))
|
|
(define (gnc:option-data-fns option)
|
|
(vector-ref option 13))
|
|
|
|
(define (gnc:option-set-changed-callback option callback)
|
|
(let ((cb-setter (vector-ref option 14)))
|
|
(cb-setter callback)))
|
|
(define (gnc:option-strings-getter option)
|
|
(vector-ref option 15))
|
|
(define (gnc:option-widget-changed-proc option)
|
|
(vector-ref option 16))
|
|
|
|
(define (gnc:option-value option)
|
|
(let ((getter (gnc:option-getter option)))
|
|
(getter)))
|
|
|
|
(define (gnc:option-set-value option value)
|
|
(let ((setter (gnc:option-setter option)))
|
|
(setter value)))
|
|
|
|
(define (gnc:option-index-get-name option index)
|
|
(let* ((option-data-fns (gnc:option-data-fns option))
|
|
(name-fn (vector-ref option-data-fns 2)))
|
|
(name-fn index)))
|
|
|
|
(define (gnc:option-index-get-description option index)
|
|
(let* ((option-data-fns (gnc:option-data-fns option))
|
|
(name-fn (vector-ref option-data-fns 3)))
|
|
(name-fn index)))
|
|
|
|
(define (gnc:option-index-get-value option index)
|
|
(let* ((option-data-fns (gnc:option-data-fns option))
|
|
(name-fn (vector-ref option-data-fns 1)))
|
|
(name-fn index)))
|
|
|
|
(define (gnc:option-value-get-index option value)
|
|
(let* ((option-data-fns (gnc:option-data-fns option))
|
|
(name-fn (vector-ref option-data-fns 4)))
|
|
(name-fn value)))
|
|
|
|
(define (gnc:option-number-of-indices option)
|
|
(let* ((option-data-fns (gnc:option-data-fns option))
|
|
(name-fn (vector-ref option-data-fns 0)))
|
|
(name-fn)))
|
|
|
|
(define (gnc:option-default-value option)
|
|
(let ((getter (gnc:option-default-getter option)))
|
|
(getter)))
|
|
|
|
;; Attention: this function can only be used with restrictions
|
|
;; - only during option generation, not in arbitrary code
|
|
;; - only for option types for which no conversion is required
|
|
;; between default-value and value. In the various gnc:make-option
|
|
;; functions below this is ok when
|
|
;; 1. there's (value default-value) in the let* call
|
|
;; 2. default-getter is set to (lambda() default-value)
|
|
(define (gnc:option-set-default-value option default-value)
|
|
(vector-set! option 7 (lambda() default-value))
|
|
(gnc:option-set-value option default-value))
|
|
|
|
|
|
(define (gnc:restore-form-generator value->string)
|
|
(lambda ()
|
|
(string-append "(lambda (o) (if o (gnc:option-set-value o "
|
|
(value->string) ")))")))
|
|
|
|
(define (gnc:value->string value)
|
|
(format #f "~s" value))
|
|
|
|
(define (gnc:make-string-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
(let* ((value default-value)
|
|
(value->string (lambda () (gnc:value->string value))))
|
|
(gnc:make-option
|
|
section name sort-tag 'string documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b value p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value v))))
|
|
(lambda (x)
|
|
(cond ((string? x)(list #t x))
|
|
(else (list #f "string-option: not a string"))))
|
|
#f #f #f #f)))
|
|
|
|
(define (gnc:make-text-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
(let* ((value default-value)
|
|
(value->string (lambda () (gnc:value->string value))))
|
|
(gnc:make-option
|
|
section name sort-tag 'text documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b value p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value v))))
|
|
(lambda (x)
|
|
(cond ((string? x)(list #t x))
|
|
(else (list #f "text-option: not a string"))))
|
|
#f #f #f #f)))
|
|
|
|
;;; font options store fonts as strings a la the X Logical
|
|
;;; Font Description. You should always provide a default
|
|
;;; value, as currently there seems to be no way to go from
|
|
;;; an actual font to a logical font description, and thus
|
|
;;; there is no way for the gui to pick a default value.
|
|
|
|
(define (gnc:make-font-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
(let* ((value default-value)
|
|
(value->string (lambda () (gnc:value->string value))))
|
|
(gnc:make-option
|
|
section
|
|
name
|
|
sort-tag
|
|
'font
|
|
documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b value p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value v))))
|
|
(lambda (x)
|
|
(cond ((string? x)(list #t x))
|
|
(else (list #f "font-option: not a string"))))
|
|
#f #f #f #f)))
|
|
|
|
;; currency options use a specialized widget for entering currencies
|
|
;; in the GUI implementation.
|
|
(define (gnc:make-currency-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
|
|
(define (currency->scm currency)
|
|
(if (string? currency)
|
|
currency
|
|
(gnc-commodity-get-mnemonic currency)))
|
|
|
|
(define (scm->currency currency)
|
|
(if (string? currency)
|
|
(gnc-commodity-table-lookup
|
|
(gnc-commodity-table-get-table (gnc-get-current-book))
|
|
GNC_COMMODITY_NS_CURRENCY currency)
|
|
currency))
|
|
|
|
(let* ((value (currency->scm default-value))
|
|
(value->string (lambda () (gnc:value->string value))))
|
|
(gnc:make-option
|
|
section name sort-tag 'currency documentation-string
|
|
(lambda () (scm->currency value))
|
|
(lambda (x) (set! value (currency->scm x)))
|
|
(lambda () (scm->currency default-value))
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b value p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value v))))
|
|
(lambda (x) (list #t x))
|
|
#f #f #f #f)))
|
|
|
|
;; budget option
|
|
;; 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)
|
|
|
|
(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
|
|
|
|
;; 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 ()
|
|
#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
|
|
;; b -- book; p -- key-path
|
|
(lambda (b p)
|
|
(qof-book-set-option
|
|
b (gncBudgetGetGUID selection-budget) p))
|
|
|
|
;; kvp->scm -- get the stored value
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(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.
|
|
(define (gnc:make-commodity-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
|
|
(define (commodity->scm commodity)
|
|
(if (string? commodity)
|
|
(list 'commodity-scm
|
|
GNC_COMMODITY_NS_CURRENCY
|
|
commodity)
|
|
(list 'commodity-scm
|
|
(gnc-commodity-get-namespace commodity)
|
|
(gnc-commodity-get-mnemonic commodity))))
|
|
|
|
(define (scm->commodity scm)
|
|
(gnc-commodity-table-lookup
|
|
(gnc-commodity-table-get-table (gnc-get-current-book))
|
|
(cadr scm) (caddr scm)))
|
|
|
|
(let* ((value (commodity->scm default-value))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'commodity documentation-string
|
|
(lambda () (scm->commodity value))
|
|
(lambda (x) (if (and (pair? x) (eqv? (car x) 'commodity-scm))
|
|
(set! value x)
|
|
(set! value (commodity->scm x))))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p)
|
|
(qof-book-set-option b (cadr value) (append p '("ns")))
|
|
(qof-book-set-option b (caddr value) (append p '("monic"))))
|
|
(lambda (b p)
|
|
(let ((ns (qof-book-get-option b (append p '("ns"))))
|
|
(monic (qof-book-get-option b (append p '("monic")))))
|
|
(if (and ns monic (string? ns) (string? monic))
|
|
(set! value (list 'commodity-scm ns monic)))))
|
|
(lambda (x) (list #t x))
|
|
#f #f #f #f)))
|
|
|
|
|
|
(define (gnc:make-simple-boolean-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
(gnc:make-complex-boolean-option section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
#f
|
|
#f))
|
|
|
|
;; Complex boolean options are the same as simple boolean options (see
|
|
;; above), with the addition of two function arguments. (If both of
|
|
;; them are #f, you have exactly a simple-boolean-option.) Both
|
|
;; functions should expect one boolean argument. When the option's
|
|
;; value is changed, the function option-widget-changed-cb will be
|
|
;; called with the new option value at the time that the GUI widget
|
|
;; representing the option is changed, and the function
|
|
;; setter-function-called-cb will be called when the option's setter
|
|
;; is called (that is, when the user selects "OK" or "Apply").
|
|
|
|
;; The option-widget-changed-cb is tested for procedurehood before
|
|
;; it is called, so it is not validated to be a procedure here.
|
|
;; However, since there could be an option-widget-changed-cb but not
|
|
;; a setter-function-called-cb, the procedurehood of the
|
|
;; setter-function-called-cb is checked here.
|
|
(define (gnc:make-complex-boolean-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
setter-function-called-cb
|
|
option-widget-changed-cb)
|
|
(let* ((value default-value)
|
|
(value->string (lambda () (gnc:value->string value))))
|
|
(gnc:make-option
|
|
section name sort-tag 'boolean documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x)
|
|
(if (procedure? setter-function-called-cb)
|
|
(setter-function-called-cb x)))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b
|
|
;; As no boolean KvpValue exists, as a workaround
|
|
;; we store the string "t" for TRUE and "f" for
|
|
;; FALSE in a string KvpValue.
|
|
(if value "t" "f")
|
|
p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
;; As no boolean KvpValue exists, as a workaround we store
|
|
;; the string "t" for TRUE and "f" for FALSE.
|
|
(cond ((equal? v "t") (set! v #t))
|
|
((equal? v "f") (set! v #f)))
|
|
(if (and v (boolean? v) (not (equal? v default-value)))
|
|
(set! value v))))
|
|
(lambda (x)
|
|
(if (boolean? x)
|
|
(list #t x)
|
|
(list #f "boolean-option: not a boolean")))
|
|
#f #f #f (and option-widget-changed-cb
|
|
(lambda (x) (option-widget-changed-cb x))))))
|
|
|
|
|
|
(define (gnc:make-pixmap-option
|
|
section name sort-tag doc-string
|
|
default-value)
|
|
(let* ((value default-value))
|
|
(gnc:make-option
|
|
section name sort-tag 'pixmap doc-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator (lambda () (gnc:value->string value)))
|
|
#f
|
|
#f
|
|
(lambda (x)
|
|
(if (string? x)
|
|
(begin
|
|
(list #t x))
|
|
(begin
|
|
(list #f "pixmap-option: not a string"))))
|
|
#f #f #f #f)))
|
|
|
|
;; show-time is boolean
|
|
;; subtype should be one of 'relative 'absolute or 'both
|
|
;; if subtype is 'absolute then relative-date-list should be #f
|
|
;; relative-date-list should be the list of relative dates permitted
|
|
;; gnc:all-relative-dates contains a list of all relative dates.
|
|
|
|
(define (gnc:make-date-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-getter
|
|
show-time
|
|
subtype
|
|
relative-date-list)
|
|
(define (date-legal date)
|
|
(and (pair? date)
|
|
(or
|
|
(and (eq? 'relative (car date)) (symbol? (cdr date)))
|
|
(and (eq? 'absolute (car date))
|
|
(or (and (pair? (cdr date)) ; we can still accept
|
|
(exact? (cadr date)) ; old-style timepairs
|
|
(exact? (cddr date)))
|
|
(and (number? (cdr date))
|
|
(exact? (cdr date))))))))
|
|
(define (maybe-convert-to-time64 date)
|
|
;; compatibility shim. this is triggered only when date is type
|
|
;; (cons 'absolute (cons sec nsec)) - we'll convert to
|
|
;; (cons 'absolute sec). this shim must always be kept for gnucash
|
|
;; to reload saved reports, or reload reports launched at startup,
|
|
;; which had been saved as timepairs.
|
|
(if (pair? (cdr date))
|
|
(cons (car date) (cadr date))
|
|
date))
|
|
(define (list-lookup full-list item)
|
|
(or (list-index (lambda (i) (eq? i item)) full-list)
|
|
(begin
|
|
(rpterror-earlier "date" item (car full-list))
|
|
0)))
|
|
(let* ((value (default-getter))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'date documentation-string
|
|
(lambda () value)
|
|
(lambda (date)
|
|
(if (date-legal date)
|
|
(set! value (maybe-convert-to-time64 date))
|
|
(gnc:error "Illegal date value set:" date)))
|
|
default-getter
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p)
|
|
(qof-book-set-option b (symbol->string (car value))
|
|
(append p '("type")))
|
|
(qof-book-set-option b
|
|
(if (symbol? (cdr value))
|
|
(symbol->string (cdr value))
|
|
(cdr value))
|
|
(append p '("value"))))
|
|
(lambda (b p)
|
|
(let ((t (qof-book-get-option b (append p '("type"))))
|
|
(v (qof-book-get-option b (append p '("value")))))
|
|
(if (and t v (string? t))
|
|
(set! value (cons (string->symbol t)
|
|
(if (string? v) (string->symbol v) v))))))
|
|
(lambda (date)
|
|
(if (date-legal date)
|
|
(list #t date)
|
|
(list #f "date-option: illegal date")))
|
|
(vector subtype show-time relative-date-list)
|
|
(vector (lambda () (length relative-date-list))
|
|
(lambda (x) (list-ref relative-date-list x))
|
|
(lambda (x) (gnc:get-relative-date-string
|
|
(list-ref relative-date-list x)))
|
|
(lambda (x) (gnc:get-relative-date-desc
|
|
(list-ref relative-date-list x)))
|
|
(lambda (x) (list-lookup relative-date-list x)))
|
|
#f
|
|
#f)))
|
|
|
|
(define (gnc:get-rd-option-data-subtype option-data)
|
|
(vector-ref option-data 0))
|
|
|
|
(define (gnc:get-rd-option-data-show-time option-data)
|
|
(vector-ref option-data 1))
|
|
|
|
(define (gnc:get-rd-option-data-rd-list option-data)
|
|
(vector-ref option-data 2))
|
|
|
|
(define (gnc:date-option-get-subtype option)
|
|
(if (eq? (gnc:option-type option) 'date)
|
|
(gnc:get-rd-option-data-subtype (gnc:option-data option))
|
|
(gnc:error "Not a date option")))
|
|
|
|
(define (gnc:date-option-show-time? option)
|
|
(if (eq? (gnc:option-type option) 'date)
|
|
(gnc:get-rd-option-data-show-time (gnc:option-data option))
|
|
(gnc:error "Not a date option")))
|
|
|
|
(define (gnc:date-option-value-type option-value)
|
|
(car option-value))
|
|
|
|
(define (gnc:date-option-absolute-time option-value)
|
|
(if (eq? (car option-value) 'absolute)
|
|
(cdr option-value)
|
|
(gnc:get-absolute-from-relative-date (cdr option-value))))
|
|
|
|
(define (gnc:date-option-relative-time option-value)
|
|
(if (eq? (car option-value) 'absolute)
|
|
#f
|
|
(cdr option-value)))
|
|
|
|
;; Just like gnc:make-account-list-limited-option except it
|
|
;; does not limit the types of accounts that are available
|
|
;; to the user.
|
|
(define (gnc:make-account-list-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-getter
|
|
value-validator
|
|
multiple-selection)
|
|
|
|
(gnc:make-account-list-limited-option
|
|
section name sort-tag documentation-string
|
|
default-getter value-validator multiple-selection '()))
|
|
|
|
;; account-list options use the option-data as a pair; the car is
|
|
;; a boolean value, the cdr is a list of account-types. If the boolean is
|
|
;; true, the gui should allow the user to select multiple accounts.
|
|
;; If the cdr is an empty list, then all account types are shown.
|
|
;; Internally, values are always a list of guids. Externally, both
|
|
;; guids and account pointers may be used to set the value of the
|
|
;; option. The option always returns a list of account pointers.
|
|
(define (gnc:make-account-list-limited-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-getter
|
|
value-validator
|
|
multiple-selection
|
|
acct-type-list)
|
|
|
|
(define (convert-to-guid item)
|
|
(if (string? item)
|
|
item
|
|
(gncAccountGetGUID item)))
|
|
|
|
(define (convert-to-account item)
|
|
(if (string? item)
|
|
(xaccAccountLookup item (gnc-get-current-book))
|
|
item))
|
|
|
|
(let* ((option (map convert-to-guid (default-getter)))
|
|
(option-set #f)
|
|
(getter (lambda () (map convert-to-account
|
|
(if option-set
|
|
option
|
|
(default-getter)))))
|
|
(value->string (lambda ()
|
|
(string-append
|
|
"'" (gnc:value->string (if option-set option #f)))))
|
|
(validator
|
|
(if (not value-validator)
|
|
(lambda (account-list) (list #t account-list))
|
|
(lambda (account-list)
|
|
(value-validator (map convert-to-account account-list))))))
|
|
(gnc:make-option
|
|
section name sort-tag 'account-list documentation-string getter
|
|
(lambda (account-list)
|
|
(if (or (not account-list) (null? account-list))
|
|
(set! account-list (default-getter)))
|
|
(set! account-list
|
|
(filter (lambda (x) (if (string? x)
|
|
(xaccAccountLookup
|
|
x (gnc-get-current-book))
|
|
x)) account-list))
|
|
(let* ((result (validator account-list))
|
|
(valid (car result))
|
|
(value (cadr result)))
|
|
(if valid
|
|
(begin
|
|
(set! option (map convert-to-guid value))
|
|
(set! option-set #t))
|
|
(gnc:error "Illegal account list value set"))))
|
|
(lambda () (map convert-to-account (default-getter)))
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p)
|
|
(when option-set
|
|
(qof-book-set-option b (length option) (append p '("len")))
|
|
(let loop ((option option) (idx 0))
|
|
(unless (null? option)
|
|
(qof-book-set-option
|
|
b (car option) (append p (list (format #f "acc~a" idx))))
|
|
(loop (cdr option) (1+ idx))))))
|
|
(lambda (b p)
|
|
(let ((len (qof-book-get-option b (append p '("len")))))
|
|
(when (and len (integer? len))
|
|
(set! option
|
|
(map
|
|
(lambda (idx)
|
|
(qof-book-get-option b (append p (list (format #f "acc~a" idx)))))
|
|
(iota len)))
|
|
(set! option-set #t))))
|
|
validator
|
|
(cons multiple-selection acct-type-list) #f #f #f)))
|
|
|
|
;; Just like gnc:make-account-sel-limited-option except it
|
|
;; does not limit the types of accounts that are available
|
|
;; to the user.
|
|
(define (gnc:make-account-sel-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-getter
|
|
value-validator)
|
|
|
|
(gnc:make-account-sel-limited-option
|
|
section name sort-tag documentation-string
|
|
default-getter value-validator '()))
|
|
|
|
;; account-sel options use the option-data as a pair; the car is
|
|
;; ignored, the cdr is a list of account-types. If the cdr is an empty
|
|
;; list, then all account types are shown. Internally, the value is
|
|
;; always a guid. Externally, both guids and account pointers may be
|
|
;; used to set the value of the option. The option always returns the
|
|
;; "current" account pointer.
|
|
(define (gnc:make-account-sel-limited-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-getter
|
|
value-validator
|
|
acct-type-list)
|
|
|
|
(define (convert-to-guid item)
|
|
(if (string? item)
|
|
item
|
|
(gncAccountGetGUID item)))
|
|
|
|
(define (convert-to-account item)
|
|
(if (string? item)
|
|
(xaccAccountLookup item (gnc-get-current-book))
|
|
item))
|
|
|
|
(define (find-first-account)
|
|
(define (find-first account-list)
|
|
(if (null? account-list)
|
|
'()
|
|
(let* ((this-account (car account-list))
|
|
(account-type (xaccAccountGetType this-account)))
|
|
(if (if (null? acct-type-list)
|
|
#t
|
|
(member account-type acct-type-list))
|
|
this-account
|
|
(find-first (cdr account-list))))))
|
|
|
|
(let* ((current-root (gnc-get-current-root-account))
|
|
(account-list (gnc-account-get-descendants-sorted current-root)))
|
|
(find-first account-list)))
|
|
|
|
(define (get-default)
|
|
(if default-getter
|
|
(default-getter)
|
|
(find-first-account)))
|
|
|
|
(let* ((option (convert-to-guid (get-default)))
|
|
(option-set #f)
|
|
(getter (lambda () (convert-to-account
|
|
(if option-set
|
|
option
|
|
(get-default)))))
|
|
(value->string (lambda ()
|
|
(string-append
|
|
(gnc:value->string (if option-set option #f)))))
|
|
(validator
|
|
(if (not value-validator)
|
|
(lambda (account) (list #t account))
|
|
(lambda (account)
|
|
(value-validator (convert-to-account account))))))
|
|
(gnc:make-option
|
|
section name sort-tag 'account-sel documentation-string getter
|
|
(lambda (account)
|
|
(if (or (not account) (null? account)) (set! account (get-default)))
|
|
(set! account (convert-to-account account))
|
|
(let* ((result (validator account))
|
|
(valid (car result))
|
|
(value (cadr result)))
|
|
(if valid
|
|
(begin
|
|
(set! option (convert-to-guid value))
|
|
(set! option-set #t))
|
|
(gnc:error "Illegal account value set"))))
|
|
(lambda () (convert-to-account (get-default)))
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b option p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! option v))))
|
|
validator
|
|
(cons #f acct-type-list) #f #f #f)))
|
|
|
|
(define (gnc:multichoice-list-lookup full-lst item)
|
|
(or (list-index (lambda (i) (eq? (vector-ref i 0) item)) full-lst)
|
|
(begin
|
|
(rpterror-earlier "multichoice" item (car full-lst))
|
|
0)))
|
|
|
|
;; multichoice options use the option-data as a list of vectors.
|
|
;; Each vector contains a permissible value (scheme symbol), a
|
|
;; name, and a description string.
|
|
(define (gnc:make-multichoice-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values)
|
|
(gnc:make-multichoice-callback-option section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values
|
|
#f
|
|
#f))
|
|
|
|
;; The multichoice-option with callback function is the same as the
|
|
;; usual multichoice options (see above), with the addition of two
|
|
;; function arguments. (If both of them are #f, you have exactly a
|
|
;; multichoice-option.) Both functions should expect one argument.
|
|
;; When the option's value is changed, the function
|
|
;; option-widget-changed-cb will be called with the new option value
|
|
;; at the time that the GUI widget representing the option is changed,
|
|
;; and the function setter-function-called-cb will be called when the
|
|
;; option's setter is called (that is, when the user selects "OK" or
|
|
;; "Apply").
|
|
(define (gnc:make-multichoice-callback-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values
|
|
setter-function-called-cb
|
|
option-widget-changed-cb)
|
|
(define (multichoice-legal val p-vals)
|
|
(cond ((null? p-vals) #f)
|
|
((eq? val (vector-ref (car p-vals) 0)) #t)
|
|
(else (multichoice-legal val (cdr p-vals)))))
|
|
|
|
(define (multichoice-strings p-vals)
|
|
(if (null? p-vals)
|
|
'()
|
|
(cons (vector-ref (car p-vals) 1)
|
|
(cons (vector-ref (car p-vals) 2)
|
|
(multichoice-strings (cdr p-vals))))))
|
|
|
|
(let* ((value default-value)
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'multichoice documentation-string
|
|
(lambda () value)
|
|
(lambda (x)
|
|
(if (multichoice-legal x ok-values)
|
|
(begin
|
|
(set! value x)
|
|
(if (procedure? setter-function-called-cb)
|
|
(setter-function-called-cb x)))
|
|
(rpterror-earlier "multichoice" x default-value)))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b (symbol->string value) p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value (string->symbol v)))))
|
|
(lambda (x)
|
|
(if (multichoice-legal x ok-values)
|
|
(list #t x)
|
|
(list #f "multichoice-option: illegal choice")))
|
|
ok-values
|
|
(vector (lambda () (length ok-values))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 0))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 1))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 2))
|
|
(lambda (x)
|
|
(gnc:multichoice-list-lookup ok-values x)))
|
|
(lambda () (multichoice-strings ok-values))
|
|
(and option-widget-changed-cb
|
|
(lambda (x) (option-widget-changed-cb x))))))
|
|
|
|
|
|
;; radiobutton options use the option-data as a list of vectors.
|
|
;; Each vector contains a permissible value (scheme symbol), a
|
|
;; name, and a description string.
|
|
(define (gnc:make-radiobutton-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values)
|
|
(gnc:make-radiobutton-callback-option section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values
|
|
#f
|
|
#f))
|
|
|
|
;; The radiobutton-option with callback function is the same as the
|
|
;; usual radiobutton options (see above), with the addition of two
|
|
;; function arguments. (If both of them are #f, you have exactly a
|
|
;; radiobutton-option.) Both functions should expect one argument.
|
|
;; When the option's value is changed, the function
|
|
;; option-widget-changed-cb will be called with the new option value
|
|
;; at the time that the GUI widget representing the option is changed,
|
|
;; and the function setter-function-called-cb will be called when the
|
|
;; option's setter is called (that is, when the user selects "OK" or
|
|
;; "Apply").
|
|
(define (gnc:make-radiobutton-callback-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values
|
|
setter-function-called-cb
|
|
option-widget-changed-cb)
|
|
(define (radiobutton-legal val p-vals)
|
|
(cond ((null? p-vals) #f)
|
|
((eq? val (vector-ref (car p-vals) 0)) #t)
|
|
(else (radiobutton-legal val (cdr p-vals)))))
|
|
|
|
(define (radiobutton-strings p-vals)
|
|
(if (null? p-vals)
|
|
'()
|
|
(cons (vector-ref (car p-vals) 1)
|
|
(cons (vector-ref (car p-vals) 2)
|
|
(radiobutton-strings (cdr p-vals))))))
|
|
|
|
(let* ((value default-value)
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'radiobutton documentation-string
|
|
(lambda () value)
|
|
(lambda (x)
|
|
(if (radiobutton-legal x ok-values)
|
|
(begin
|
|
(set! value x)
|
|
(if (procedure? setter-function-called-cb)
|
|
(setter-function-called-cb x)))
|
|
(rpterror-earlier "radiobutton" x default-value)))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b (symbol->string value) p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (string? v))
|
|
(set! value (string->symbol v)))))
|
|
(lambda (x)
|
|
(if (radiobutton-legal x ok-values)
|
|
(list #t x)
|
|
(list #f "radiobutton-option: illegal choice")))
|
|
ok-values
|
|
(vector (lambda () (length ok-values))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 0))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 1))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 2))
|
|
(lambda (x)
|
|
(gnc:multichoice-list-lookup ok-values x)))
|
|
(lambda () (radiobutton-strings ok-values))
|
|
(and option-widget-changed-cb
|
|
(lambda (x) (option-widget-changed-cb x))))))
|
|
|
|
|
|
;; list options use the option-data in the same way as multichoice
|
|
;; options. List options allow the user to select more than one option.
|
|
(define (gnc:make-list-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
ok-values)
|
|
|
|
(define (legal-value? value legal-values)
|
|
(cond ((null? legal-values) #f)
|
|
((eq? value (vector-ref (car legal-values) 0)) #t)
|
|
(else (legal-value? value (cdr legal-values)))))
|
|
|
|
(define (list-legal values)
|
|
(cond ((null? values) #t)
|
|
(else
|
|
(and
|
|
(legal-value? (car values) ok-values)
|
|
(list-legal (cdr values))))))
|
|
|
|
(define (list-strings p-vals)
|
|
(if (null? p-vals)
|
|
'()
|
|
(cons (vector-ref (car p-vals) 1)
|
|
(cons (vector-ref (car p-vals) 2)
|
|
(list-strings (cdr p-vals))))))
|
|
|
|
(let* ((value default-value)
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'list documentation-string
|
|
(lambda () value)
|
|
(lambda (x)
|
|
(if (list-legal x)
|
|
(set! value x)
|
|
(rpterror-earlier "list" x default-value)))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p)
|
|
(qof-book-set-option b (length value) (append p '("len")))
|
|
(let loop ((value value) (idx 0))
|
|
(unless (null? value)
|
|
(qof-book-set-option
|
|
b (caar value) (append p (list (format #f "item~a" idx))))
|
|
(loop (cdr value) (1+ idx)))))
|
|
(lambda (b p)
|
|
(let ((len (qof-book-get-option b (append p '("len")))))
|
|
(if (and len (integer? len))
|
|
(set! value
|
|
(map
|
|
(lambda (idx)
|
|
(qof-book-get-option b (append p (list (format #f "item~a" idx)))))
|
|
(iota len))))))
|
|
(lambda (x)
|
|
(if (list-legal x)
|
|
(list #t x)
|
|
(list #f "list-option: illegal value")))
|
|
ok-values
|
|
(vector (lambda () (length ok-values))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 0))
|
|
(lambda (x) (vector-ref (list-ref ok-values x) 1))
|
|
(lambda (x) (vector-ref (ref ok-values x) 2))
|
|
(lambda (x) (gnc:multichoice-list-lookup ok-values x)))
|
|
(lambda () (list-strings ok-values)) #f)))
|
|
|
|
;; number range options use the option-data as a list whose
|
|
;; elements are: (lower-bound upper-bound num-decimals step-size)
|
|
(define (gnc:make-number-range-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
lower-bound
|
|
upper-bound
|
|
num-decimals
|
|
step-size)
|
|
(let* ((value default-value)
|
|
(value->string (lambda () (number->string value))))
|
|
(gnc:make-option
|
|
section name sort-tag 'number-range documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) (qof-book-set-option b value p))
|
|
(lambda (b p)
|
|
(let ((v (qof-book-get-option b p)))
|
|
(if (and v (number? v))
|
|
(set! value v))))
|
|
(lambda (x)
|
|
(cond ((not (number? x)) (list #f "number-range-option: not a number"))
|
|
((and (>= value lower-bound)
|
|
(<= value upper-bound))
|
|
(list #t x))
|
|
(else (list #f "number-range-option: out of range"))))
|
|
(list lower-bound upper-bound num-decimals step-size)
|
|
#f #f #f)))
|
|
|
|
;; number plot size options use the option-data as a list whose
|
|
;; elements are: (lower-bound upper-bound num-decimals step-size)
|
|
;; which is used for the valid pixel range
|
|
(define (gnc:make-number-plot-size-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
lower-bound
|
|
upper-bound
|
|
num-decimals
|
|
step-size)
|
|
(let* ((value default-value)
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'plot-size documentation-string
|
|
(lambda () value) ;;getter
|
|
(lambda (x)
|
|
(if (number? x) ;; this is for old style plot size
|
|
(set! value (cons 'pixels x))
|
|
(set! value x))) ;;setter
|
|
|
|
(lambda () default-value) ;;default-getter
|
|
(gnc:restore-form-generator value->string) ;;restore-form
|
|
(lambda (b p)
|
|
(qof-book-set-option b (symbol->string (car value))
|
|
(append p '("type")))
|
|
(qof-book-set-option b (if (symbol? (cdr value))
|
|
(symbol->string (cdr value))
|
|
(cdr value))
|
|
(append p '("value")))) ;;scm->kvp
|
|
(lambda (b p)
|
|
(let ((t (qof-book-get-option b (append p '("type"))))
|
|
(v (qof-book-get-option b (append p '("value")))))
|
|
(if (and t v (string? t))
|
|
(set! value (cons (string->symbol t)
|
|
(if (string? v) (string->number v) v)))))) ;;kvp->scm
|
|
(lambda (x)
|
|
(if (eq? 'pixels (car x))
|
|
(cond ((not (number? (cdr x))) (list #f "number-plot-size-option-pixels: not a number"))
|
|
((and (>= (cdr x) lower-bound)
|
|
(<= (cdr x) upper-bound))
|
|
(list #t x))
|
|
(else (list #f "number-plot-size-option-pixels: out of range")))
|
|
(cond ((not (number? (cdr x))) (list #f "number-plot-size-option-percentage: not a number"))
|
|
((and (>= (cdr x) 10)
|
|
(<= (cdr x) 100))
|
|
(list #t x))
|
|
(else (list #f "number-plot-size-option-percentage: out of range")))
|
|
)
|
|
) ;;value-validator
|
|
(list lower-bound upper-bound num-decimals step-size) ;;option-data
|
|
#f #f #f))) ;;option-data-fns, strings-getter, option-widget-changed-proc
|
|
|
|
(define (gnc:plot-size-option-value-type option-value)
|
|
(car option-value))
|
|
|
|
(define (gnc:plot-size-option-value option-value)
|
|
(cdr option-value))
|
|
|
|
(define (gnc:make-internal-option
|
|
section
|
|
name
|
|
default-value)
|
|
(let* ((value default-value)
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name "" 'internal #f
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () default-value)
|
|
(gnc:restore-form-generator value->string)
|
|
#f
|
|
#f
|
|
(lambda (x) (list #t x))
|
|
#f #f #f #f)))
|
|
|
|
|
|
(define (gnc:make-query-option
|
|
section
|
|
name
|
|
default-value)
|
|
(let* ((value (if (list? default-value)
|
|
default-value
|
|
(gnc-query2scm default-value)))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name "" 'query #f
|
|
(lambda () value)
|
|
(lambda (x) (set! value (if (list? x) x (gnc-query2scm x))))
|
|
(lambda () (if (list? default-value)
|
|
default-value
|
|
(gnc-query2scm default-value)))
|
|
(gnc:restore-form-generator value->string)
|
|
#f
|
|
#f
|
|
(lambda (x) (list #t x))
|
|
#f #f #f #f)))
|
|
|
|
|
|
;; Color options store rgba values in a list.
|
|
;; The option-data is a list, whose first element
|
|
;; is the range of possible rgba values and whose
|
|
;; second element is a boolean indicating whether
|
|
;; to use alpha transparency.
|
|
(define (gnc:make-color-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value
|
|
range
|
|
use-alpha)
|
|
|
|
(define (canonicalize values)
|
|
(map exact->inexact values))
|
|
|
|
(define (values-in-range values)
|
|
(if (null? values)
|
|
#t
|
|
(let ((value (car values)))
|
|
(and (number? value)
|
|
(>= value 0)
|
|
(<= value range)
|
|
(values-in-range (cdr values))))))
|
|
|
|
(define (validate-color color)
|
|
(cond ((not (list? color)) (list #f "color-option: not a list"))
|
|
((not (= 4 (length color))) (list #f "color-option: wrong length"))
|
|
((not (values-in-range color))
|
|
(list #f "color-option: bad color values"))
|
|
(else (list #t color))))
|
|
|
|
(let* ((value (canonicalize default-value))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'color documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value (canonicalize x)))
|
|
(lambda () (canonicalize default-value))
|
|
(gnc:restore-form-generator value->string)
|
|
#f
|
|
#f
|
|
validate-color
|
|
(list range use-alpha)
|
|
#f #f #f)))
|
|
|
|
(define (gnc:color->hex-string color range)
|
|
(define (html-value value)
|
|
(inexact->exact
|
|
(min 255.0
|
|
(truncate (* (/ 255.0 range) value)))))
|
|
(define (number->hex-string number)
|
|
(let ((ret (number->string number 16)))
|
|
(cond ((< (string-length ret) 2) (string-append "0" ret))
|
|
(else ret))))
|
|
(let ((red (car color))
|
|
(green (cadr color))
|
|
(blue (caddr color)))
|
|
(string-append
|
|
(number->hex-string (html-value red))
|
|
(number->hex-string (html-value green))
|
|
(number->hex-string (html-value blue)))))
|
|
|
|
(define (gnc:color->html color range)
|
|
(string-append "#"
|
|
(gnc:color->hex-string color range)))
|
|
|
|
(define (gnc:color-option->html color-option)
|
|
(let ((color (gnc:option-value color-option))
|
|
(range (car (gnc:option-data color-option))))
|
|
(gnc:color->html color range)))
|
|
|
|
(define (gnc:color-option->hex-string color-option)
|
|
(let ((color (gnc:option-value color-option))
|
|
(range (car (gnc:option-data color-option))))
|
|
(gnc:color->hex-string color range)))
|
|
|
|
;;
|
|
;; dateformat option
|
|
;;
|
|
(define (gnc:make-dateformat-option
|
|
section
|
|
name
|
|
sort-tag
|
|
documentation-string
|
|
default-value)
|
|
|
|
(define (def-value)
|
|
(if (list? default-value)
|
|
default-value
|
|
(list 'unset 'number #t "")))
|
|
|
|
(let* ((value (def-value))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string value)))))
|
|
(gnc:make-option
|
|
section name sort-tag 'dateformat documentation-string
|
|
(lambda () value)
|
|
(lambda (x) (set! value x))
|
|
(lambda () (def-value))
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p)
|
|
(if (eq? (car value) 'unset)
|
|
(qof-book-options-delete b p );; delete the kvp when unset
|
|
(begin
|
|
(qof-book-set-option
|
|
b (symbol->string (car value)) (append p '("fmt")))
|
|
(qof-book-set-option
|
|
b (symbol->string (cadr value)) (append p '("month")))
|
|
(qof-book-set-option
|
|
b (if (caddr value) 1 0) (append p '("years")))
|
|
(qof-book-set-option
|
|
b (cadddr value) (append p '("custom"))))))
|
|
(lambda (f p)
|
|
(let ((fmt (qof-book-get-option f (append p '("fmt"))))
|
|
(month (qof-book-get-option f (append p '("month"))))
|
|
(years (qof-book-get-option f (append p '("years"))))
|
|
(custom (qof-book-get-option f (append p '("custom")))))
|
|
(if (and
|
|
fmt (string? fmt)
|
|
month (string? month)
|
|
years (number? years)
|
|
custom (string? custom))
|
|
(set! value (list (string->symbol fmt) (string->symbol month)
|
|
(if (= years 0) #f #t) custom)))))
|
|
(lambda (x)
|
|
(cond ((not (list? x)) (list #f "dateformat-option: not a list"))
|
|
((not (= (length x) 4))
|
|
(list #f "dateformat-option: wrong list length" (length x)))
|
|
((not (symbol? (car x)))
|
|
(list #f "dateformat-option: no format symbol"))
|
|
((not (symbol? (cadr x)))
|
|
(list #f "dateformat-option: no months symbol"))
|
|
((not (string? (cadddr x)))
|
|
(list #f "dateformat-option: no custom string"))
|
|
(else (list #t x))))
|
|
#f #f #f #f)))
|
|
|
|
(define (gnc:dateformat-get-format v)
|
|
(cadddr v))
|
|
|
|
(define (gnc:make-currency-accounting-option
|
|
section
|
|
name
|
|
sort-tag
|
|
radiobutton-documentation-string
|
|
default-radiobutton-value
|
|
ok-radiobutton-values
|
|
book-currency-documentation-string
|
|
default-book-currency-value
|
|
default-cap-gains-policy-documentation-string
|
|
default-cap-gains-policy-value
|
|
default-gains-loss-account-documentation-string
|
|
)
|
|
(define (legal-val val p-vals)
|
|
(cond ((null? p-vals) #f)
|
|
((not (symbol? val)) #f)
|
|
((eq? val (vector-ref (car p-vals) 0)) #t)
|
|
(else (legal-val val (cdr p-vals)))))
|
|
|
|
(define (currency-lookup currency-string)
|
|
(if (string? currency-string)
|
|
(gnc-commodity-table-lookup
|
|
(gnc-commodity-table-get-table (gnc-get-current-book))
|
|
GNC_COMMODITY_NS_CURRENCY currency-string)
|
|
#f))
|
|
|
|
(define (currency? val)
|
|
(gnc-commodity-is-currency (currency-lookup val)))
|
|
|
|
(define (vector-strings p-vals)
|
|
(if (null? p-vals)
|
|
'()
|
|
(cons (vector-ref (car p-vals) 1)
|
|
(cons (vector-ref (car p-vals) 2)
|
|
(vector-strings (cdr p-vals))))))
|
|
|
|
(define (currency->scm currency)
|
|
(if (string? currency)
|
|
currency
|
|
(gnc-commodity-get-mnemonic currency)))
|
|
|
|
(define (scm->currency currency)
|
|
(currency-lookup currency))
|
|
|
|
(define (valid-gains-loss-account? book-currency gains-loss-account-guid)
|
|
;; xaccAccountLookup returns Account if guid valid otherwise NULL; also must
|
|
;; be in book-currency, income or expense, and not placeholder nor hidden
|
|
(let* ((account (xaccAccountLookup gains-loss-account-guid
|
|
(gnc-get-current-book))))
|
|
(and account
|
|
(not (null? account))
|
|
(not (xaccAccountIsHidden account))
|
|
(not (xaccAccountGetPlaceholder account))
|
|
(memv (xaccAccountGetType account)
|
|
(list ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE))
|
|
(gnc-commodity-equal
|
|
(currency-lookup book-currency)
|
|
(xaccAccountGetCommodity account)))))
|
|
|
|
(let* ((value (if (eq? 'book-currency default-radiobutton-value)
|
|
(list default-radiobutton-value
|
|
default-book-currency-value
|
|
default-cap-gains-policy-value)
|
|
(list default-radiobutton-value)))
|
|
(value->string (lambda ()
|
|
(string-append "'" (gnc:value->string
|
|
(car value)))))
|
|
(trading-accounts-path (list gnc:*option-section-accounts*
|
|
gnc:*option-name-trading-accounts*))
|
|
(book-currency-path (list gnc:*option-section-accounts*
|
|
gnc:*option-name-book-currency*))
|
|
(gains-policy-path (list gnc:*option-section-accounts*
|
|
gnc:*option-name-default-gains-policy*))
|
|
(gains-loss-account-path (list gnc:*option-section-accounts*
|
|
gnc:*option-name-default-gain-loss-account*)))
|
|
(gnc:make-option
|
|
section name sort-tag 'currency-accounting
|
|
radiobutton-documentation-string
|
|
(lambda () value) ;; getter
|
|
(lambda (x)
|
|
(if (legal-val (car x) ok-radiobutton-values)
|
|
(set! value x)
|
|
(gnc:error "Illegal Radiobutton option set"))) ;;setter
|
|
(lambda () (if (eq? 'book-currency default-radiobutton-value)
|
|
(list default-radiobutton-value
|
|
default-book-currency-value
|
|
default-cap-gains-policy-value)
|
|
(list default-radiobutton-value))) ;; default-getter
|
|
(gnc:restore-form-generator value->string)
|
|
(lambda (b p) ;; scm->kvp
|
|
(case (car value)
|
|
((book-currency)
|
|
;; Currency = selected currency
|
|
(qof-book-set-option b (currency->scm (cadr value))
|
|
book-currency-path)
|
|
;; Default Gains Policy = selected policy
|
|
(qof-book-set-option b (symbol->string (caddr value))
|
|
gains-policy-path)
|
|
;; Default Gains Account = if selected, selected account
|
|
(if (car (cdddr value))
|
|
(qof-book-set-option b (car (cdddr value))
|
|
gains-loss-account-path)))
|
|
((trading)
|
|
;; Use Trading Accounts = "t"
|
|
(qof-book-set-option b "t" trading-accounts-path))))
|
|
(lambda (b p) ;; kvp->scm
|
|
(let* ((trading-option-path-kvp?
|
|
(qof-book-get-option b trading-accounts-path))
|
|
(trading? (and trading-option-path-kvp?
|
|
(string=? "t" trading-option-path-kvp?)))
|
|
(book-currency #f)
|
|
(cap-gains-policy #f)
|
|
(gains-loss-account-guid #f)
|
|
(v (if trading?
|
|
'trading
|
|
(let* ((book-currency-option-path-kvp?
|
|
(qof-book-get-option
|
|
b book-currency-path))
|
|
(gains-policy-option-path-kvp?
|
|
(qof-book-get-option
|
|
b gains-policy-path))
|
|
(gains-loss-account-option-path-kvp?
|
|
(qof-book-get-option
|
|
b gains-loss-account-path))
|
|
(book-currency?
|
|
(if (and book-currency-option-path-kvp?
|
|
gains-policy-option-path-kvp?
|
|
(string?
|
|
book-currency-option-path-kvp?)
|
|
(string?
|
|
gains-policy-option-path-kvp?)
|
|
(if book-currency-option-path-kvp?
|
|
(currency?
|
|
book-currency-option-path-kvp?))
|
|
(if gains-policy-option-path-kvp?
|
|
(gnc-valid-policy-name
|
|
gains-policy-option-path-kvp?)))
|
|
(begin
|
|
(set! book-currency
|
|
book-currency-option-path-kvp?)
|
|
(set! cap-gains-policy
|
|
gains-policy-option-path-kvp?)
|
|
(if gains-loss-account-option-path-kvp?
|
|
(if (valid-gains-loss-account?
|
|
book-currency
|
|
gains-loss-account-option-path-kvp?)
|
|
(set! gains-loss-account-guid
|
|
gains-loss-account-option-path-kvp?)))
|
|
#t)
|
|
#f)))
|
|
(if book-currency?
|
|
'book-currency
|
|
'neither)))))
|
|
(if (and v (symbol? v) (legal-val v ok-radiobutton-values))
|
|
(set! value (cons v (if (eq? 'book-currency v)
|
|
(list (scm->currency book-currency)
|
|
(string->symbol cap-gains-policy)
|
|
gains-loss-account-guid)
|
|
'())))
|
|
(set! value (list 'neither)))))
|
|
(lambda (x) ;; value validator
|
|
(cond
|
|
((not (list? x))
|
|
(list #f "value not a list"))
|
|
((not (legal-val (car x) ok-radiobutton-values))
|
|
(list #f "radiobutton-option: illegal choice"))
|
|
((not (eq? 'book-currency (car x)))
|
|
(list #t x))
|
|
((not (currency? (currency->scm (cadr x))))
|
|
(list #f "currency-option: illegal value"))
|
|
((not (gnc-valid-policy-name (symbol->string (caddr x))))
|
|
(list #f "cap-gains-policy-option: illegal value"))
|
|
((not (car (cdddr x)))
|
|
(list #t x))
|
|
((not (valid-gains-loss-account? (currency->scm (cadr x))
|
|
(car (cdddr x))))
|
|
(list #f "gains-loss-account-option: illegal value"))
|
|
(else
|
|
(list #t x))))
|
|
(vector book-currency-documentation-string
|
|
default-book-currency-value
|
|
default-cap-gains-policy-documentation-string
|
|
default-cap-gains-policy-value
|
|
default-gains-loss-account-documentation-string)
|
|
(vector (lambda () (length ok-radiobutton-values))
|
|
(lambda (x) (vector-ref (list-ref ok-radiobutton-values x) 0))
|
|
(lambda (x) (vector-ref (list-ref ok-radiobutton-values x) 1))
|
|
(lambda (x) (vector-ref (list-ref ok-radiobutton-values x) 2))
|
|
(lambda (x)
|
|
(gnc:multichoice-list-lookup ok-radiobutton-values x)))
|
|
(lambda () (vector-strings ok-radiobutton-values))
|
|
#f)))
|
|
|
|
(define (gnc:get-currency-accounting-option-data-curr-doc-string option-data)
|
|
(vector-ref option-data 0))
|
|
|
|
(define (gnc:get-currency-accounting-option-data-default-curr option-data)
|
|
(vector-ref option-data 1))
|
|
|
|
(define (gnc:get-currency-accounting-option-data-policy-doc-string option-data)
|
|
(vector-ref option-data 2))
|
|
|
|
(define (gnc:get-currency-accounting-option-data-policy-default option-data)
|
|
(vector-ref option-data 3))
|
|
|
|
(define (gnc:get-currency-accounting-option-data-gain-loss-account-doc-string option-data)
|
|
(vector-ref option-data 4))
|
|
|
|
(define (gnc:currency-accounting-option-get-curr-doc-string option)
|
|
(if (eq? (gnc:option-type option) 'currency-accounting)
|
|
(gnc:get-currency-accounting-option-data-curr-doc-string
|
|
(gnc:option-data option))
|
|
(gnc:error "Not a currency accounting option")))
|
|
|
|
(define (gnc:currency-accounting-option-get-default-curr option)
|
|
(if (eq? (gnc:option-type option) 'currency-accounting)
|
|
(gnc:get-currency-accounting-option-data-default-curr
|
|
(gnc:option-data option))
|
|
(gnc:error "Not a currency accounting option")))
|
|
|
|
(define (gnc:currency-accounting-option-get-policy-doc-string option)
|
|
(if (eq? (gnc:option-type option) 'currency-accounting)
|
|
(gnc:get-currency-accounting-option-data-policy-doc-string
|
|
(gnc:option-data option))
|
|
(gnc:error "Not a currency accounting option")))
|
|
|
|
(define (gnc:currency-accounting-option-get-default-policy option)
|
|
(if (eq? (gnc:option-type option) 'currency-accounting)
|
|
(gnc:get-currency-accounting-option-data-policy-default
|
|
(gnc:option-data option))
|
|
(gnc:error "Not a currency accounting option")))
|
|
|
|
(define (gnc:currency-accounting-option-get-gain-loss-account-doc-string option)
|
|
(if (eq? (gnc:option-type option) 'currency-accounting)
|
|
(gnc:get-currency-accounting-option-data-gain-loss-account-doc-string
|
|
(gnc:option-data option))
|
|
(gnc:error "Not a currency accounting option")))
|
|
|
|
(define (gnc:currency-accounting-option-selected-method option-value)
|
|
(car option-value))
|
|
|
|
(define (gnc:currency-accounting-option-selected-currency option-value)
|
|
(if (eq? (car option-value) 'book-currency)
|
|
(cadr option-value)
|
|
#f))
|
|
|
|
(define (gnc:currency-accounting-option-selected-policy option-value)
|
|
(if (eq? (car option-value) 'book-currency)
|
|
(caddr option-value)
|
|
#f))
|
|
|
|
(define (gnc:currency-accounting-option-selected-gain-loss-account option-value)
|
|
(if (eq? (car option-value) 'book-currency)
|
|
(car (cdddr option-value))
|
|
#f))
|
|
|
|
;; Create a new options database
|
|
(define (gnc:new-options)
|
|
(define option-hash (make-hash-table 23))
|
|
|
|
(define options-changed #f)
|
|
(define changed-hash (make-hash-table 23))
|
|
|
|
(define callback-hash (make-hash-table 23))
|
|
(define last-callback-id 0)
|
|
(define new-names-alist
|
|
'(("Accounts to include" #f "Accounts")
|
|
("Exclude transactions between selected accounts?" #f
|
|
"Exclude transactions between selected accounts")
|
|
("Filter Accounts" #f "Filter By...")
|
|
("Flatten list to depth limit?" #f "Flatten list to depth limit")
|
|
("From" #f "Start Date")
|
|
("Report Accounts" #f "Accounts")
|
|
("Report Currency" #f "Report's currency")
|
|
("Show Account Code?" #f "Show Account Code")
|
|
("Show Full Account Name?" #f "Show Full Account Name")
|
|
("Show Multi-currency Totals?" #f "Show Multi-currency Totals")
|
|
("Show zero balance items?" #f "Show zero balance items")
|
|
("Sign Reverses?" #f "Sign Reverses")
|
|
("To" #f "End Date")
|
|
("Charge Type" #f "Action") ;easy-invoice.scm, renamed June 2018
|
|
;; the following 4 options in income-gst-statement.scm renamed Dec 2018
|
|
("Individual income columns" #f "Individual sales columns")
|
|
("Individual expense columns" #f "Individual purchases columns")
|
|
("Remittance amount" #f "Gross Balance")
|
|
("Net Income" #f "Net Balance")
|
|
;; transaction.scm:
|
|
("Use Full Account Name?" #f "Use Full Account Name")
|
|
("Use Full Other Account Name?" #f "Use Full Other Account Name")
|
|
("Void Transactions?" "Filter" "Void Transactions")
|
|
("Void Transactions" "Filter" "Void Transactions")
|
|
("Account Substring" "Filter" "Account Name Filter")
|
|
("Enable links" #f "Enable Links")
|
|
;; invoice.scm, renamed November 2018
|
|
("Individual Taxes" #f "Use Detailed Tax Summary")
|
|
;; income-gst-statement.scm
|
|
("default format" #f "Default Format")
|
|
))
|
|
|
|
(define (lookup-option section name)
|
|
(let ((section-hash (hash-ref option-hash section)))
|
|
(and section-hash
|
|
(or (hash-ref section-hash name)
|
|
;; Option name was not found. Perhaps it was renamed?
|
|
;; Let's try to map to a known new name. The alist
|
|
;; new-names-alist will try match names - car is the old
|
|
;; name, cdr is the 2-element list describing
|
|
;; newsection newname. If newsection is #f then reuse
|
|
;; previous section name. Please note the rename list
|
|
;; currently supports renaming individual option names,
|
|
;; or individual option names moved to another
|
|
;; section. It does not currently support renaming
|
|
;; whole sections.
|
|
(let ((name-match (assoc-ref new-names-alist name)))
|
|
(and name-match
|
|
(let ((new-section (car name-match))
|
|
(new-name (cadr name-match)))
|
|
(gnc:debug
|
|
(format #f "option ~a/~a has been renamed to ~a/~a\n"
|
|
section name new-section new-name))
|
|
(cond
|
|
;; new-name only
|
|
((not new-section)
|
|
(lookup-option section new-name))
|
|
;; new-section different to current section
|
|
;; name, and possibly new-name
|
|
((not (string=? new-section section))
|
|
(lookup-option new-section new-name))
|
|
;; no match, return #f
|
|
(else #f)))))))))
|
|
|
|
(define (option-changed section name)
|
|
(set! options-changed #t)
|
|
(let ((section-changed-hash (hash-ref changed-hash section)))
|
|
(if (not section-changed-hash)
|
|
(begin
|
|
(set! section-changed-hash (make-hash-table 23))
|
|
(hash-set! changed-hash section section-changed-hash)))
|
|
(hash-set! section-changed-hash name #t)))
|
|
|
|
(define (clear-changes)
|
|
(set! options-changed #f)
|
|
(set! changed-hash (make-hash-table 23)))
|
|
|
|
(define (register-option new-option)
|
|
(let* ((name (gnc:option-name new-option))
|
|
(section (gnc:option-section new-option))
|
|
(section-hash (hash-ref option-hash section)))
|
|
(if (not section-hash)
|
|
(begin
|
|
(set! section-hash (make-hash-table 23))
|
|
(hash-set! option-hash section section-hash)))
|
|
(hash-set! section-hash name new-option)
|
|
(gnc:option-set-changed-callback
|
|
new-option
|
|
(lambda () (option-changed section name)))))
|
|
|
|
(define (unregister-option section name)
|
|
(let* ((section-hash (hash-ref option-hash section)))
|
|
(if (and section-hash
|
|
(hash-ref section-hash name))
|
|
(begin
|
|
(hash-remove! section-hash name)
|
|
(if (zero? (hash-count (const #t) section-hash))
|
|
(hash-remove! option-hash section)))
|
|
(gnc:error "options:unregister-option: no such option\n"))))
|
|
|
|
; Call (thunk option) for each option in the database
|
|
(define (options-for-each thunk)
|
|
(define (section-for-each section-hash thunk)
|
|
(hash-for-each
|
|
(lambda (name option)
|
|
(thunk option))
|
|
section-hash))
|
|
(hash-for-each
|
|
(lambda (section hash)
|
|
(section-for-each hash thunk))
|
|
option-hash))
|
|
|
|
(define (options-for-each-general section-thunk option-thunk)
|
|
(define (section-for-each section-hash thunk)
|
|
(hash-for-each
|
|
(lambda (name option)
|
|
(thunk option))
|
|
section-hash))
|
|
(hash-for-each
|
|
(lambda (section hash)
|
|
(if section-thunk
|
|
(section-thunk section hash))
|
|
(if option-thunk
|
|
(section-for-each hash option-thunk)))
|
|
option-hash))
|
|
|
|
(define (generate-restore-forms options-string)
|
|
|
|
(define (generate-option-restore-form option restore-code)
|
|
(let* ((section (gnc:option-section option))
|
|
(name (gnc:option-name option)))
|
|
(string-append
|
|
"(let ((option (gnc:lookup-option " options-string "\n"
|
|
" " (gnc:value->string section) "\n"
|
|
" " (gnc:value->string name) ")))\n"
|
|
" (" restore-code " option))\n\n")))
|
|
|
|
(define (generate-forms port)
|
|
(options-for-each-general
|
|
(lambda (section hash)
|
|
(display
|
|
(string-append "\n; Section: " section "\n\n")
|
|
port))
|
|
(lambda (option)
|
|
(let ((value (gnc:option-value option))
|
|
(default-value (gnc:option-default-value option)))
|
|
(if (not (equal? value default-value))
|
|
(let* ((generator (gnc:option-generate-restore-form option))
|
|
(restore-code (false-if-exception (generator))))
|
|
(if restore-code
|
|
(display
|
|
(generate-option-restore-form option restore-code)
|
|
port))))))))
|
|
|
|
(call-with-output-string generate-forms))
|
|
|
|
(define (scm->kvp book)
|
|
(options-for-each
|
|
(lambda (option)
|
|
(let ((value (gnc:option-value option))
|
|
(default-value (gnc:option-default-value option))
|
|
(section (gnc:option-section option))
|
|
(name (gnc:option-name option)))
|
|
;; (gnc:debug "value: " value "; default: " default-value
|
|
;; "; section: " section "; name: " name)
|
|
(if (not (equal? value default-value))
|
|
(let ((save-fcn (gnc:option-scm->kvp option)))
|
|
;; (gnc:debug "save-fcn: " save-fcn)
|
|
(if save-fcn
|
|
(save-fcn book (list section name)))))))))
|
|
|
|
(define (kvp->scm book)
|
|
(options-for-each
|
|
(lambda (option)
|
|
(let ((section (gnc:option-section option))
|
|
(name (gnc:option-name option))
|
|
(load-fcn (gnc:option-kvp->scm option)))
|
|
(if load-fcn
|
|
(load-fcn book (list section name)))))))
|
|
|
|
(define (register-callback section name callback)
|
|
(let ((id last-callback-id)
|
|
(data (list section name callback)))
|
|
(set! last-callback-id (+ last-callback-id 1))
|
|
(hashv-set! callback-hash id data)
|
|
id))
|
|
|
|
(define (unregister-callback-id id)
|
|
(if (hashv-ref callback-hash id)
|
|
(hashv-remove! callback-hash id)
|
|
(gnc:error "options:unregister-callback-id: no such id\n")))
|
|
|
|
(define (run-callbacks)
|
|
(define (run-callback id cbdata)
|
|
(let ((section (car cbdata))
|
|
(name (cadr cbdata))
|
|
(callback (caddr cbdata)))
|
|
(if (not section)
|
|
(callback)
|
|
(let ((section-changed-hash (hash-ref changed-hash section)))
|
|
(if section-changed-hash
|
|
(if (not name)
|
|
(callback)
|
|
(if (hash-ref section-changed-hash name)
|
|
(callback))))))))
|
|
|
|
(if options-changed
|
|
(let ((cblist '()))
|
|
(hash-for-each
|
|
(lambda (k v) (set! cblist (cons (cons k v) cblist)))
|
|
callback-hash)
|
|
(set! cblist (sort cblist
|
|
(lambda (a b)
|
|
(< (car a) (car b)))))
|
|
(for-each
|
|
(lambda (elt) (run-callback (car elt) (cdr elt)))
|
|
cblist)))
|
|
(clear-changes))
|
|
|
|
(define default-section #f)
|
|
|
|
(define (touch)
|
|
(set! options-changed #t)
|
|
(run-callbacks))
|
|
|
|
(define (set-default-section section-name)
|
|
(set! default-section section-name))
|
|
|
|
(define (get-default-section)
|
|
default-section)
|
|
|
|
(define (dispatch key)
|
|
(case key
|
|
((lookup) lookup-option)
|
|
((register-option) register-option)
|
|
((unregister-option) unregister-option)
|
|
((register-callback) register-callback)
|
|
((unregister-callback-id) unregister-callback-id)
|
|
((for-each) options-for-each)
|
|
((for-each-general) options-for-each-general)
|
|
((generate-restore-forms) generate-restore-forms)
|
|
((scm->kvp) scm->kvp)
|
|
((kvp->scm) kvp->scm)
|
|
((touch) touch)
|
|
((clear-changes) clear-changes)
|
|
((run-callbacks) run-callbacks)
|
|
((set-default-section) set-default-section)
|
|
((get-default-section) get-default-section)
|
|
(else (gnc:warn "options: bad key: " key "\n"))))
|
|
|
|
dispatch)
|
|
|
|
(define (gnc:register-option options new-option)
|
|
((options 'register-option) new-option))
|
|
|
|
(define (gnc:options-register-callback section name callback options)
|
|
((options 'register-callback) section name callback))
|
|
|
|
(define (gnc:options-register-c-callback section name c-callback data options)
|
|
(let ((callback (lambda () (gncp-option-invoke-callback c-callback data))))
|
|
((options 'register-callback) section name callback)))
|
|
|
|
(define (gnc:options-unregister-callback-id id options)
|
|
((options 'unregister-callback-id) id))
|
|
|
|
(define (gnc:options-for-each thunk options)
|
|
((options 'for-each) thunk))
|
|
|
|
(define (gnc:options-for-each-general section-thunk option-thunk options)
|
|
((options 'for-each-general) section-thunk option-thunk))
|
|
|
|
(define (gnc:lookup-option options section name)
|
|
(if options
|
|
((options 'lookup) section name)
|
|
#f))
|
|
|
|
(define (gnc:unregister-option options section name)
|
|
((options 'unregister-option) section name))
|
|
|
|
(define (gnc:generate-restore-forms options options-string)
|
|
((options 'generate-restore-forms) options-string))
|
|
|
|
(define (gnc:options-fancy-date book)
|
|
(let ((date-format (gnc:fancy-date-info book gnc:*fancy-date-format*)))
|
|
(if (boolean? date-format) ;; date-format does not exist
|
|
(qof-date-format-get-string (qof-date-format-get))
|
|
date-format)))
|
|
|
|
(define (gnc:options-scm->kvp options book clear-option?)
|
|
(if clear-option?
|
|
(qof-book-options-delete book '()))
|
|
((options 'scm->kvp) book))
|
|
|
|
(define (gnc:options-kvp->scm options book)
|
|
((options 'kvp->scm) book))
|
|
|
|
(define (gnc:options-clear-changes options)
|
|
((options 'clear-changes)))
|
|
|
|
(define (gnc:options-touch options)
|
|
((options 'touch)))
|
|
|
|
(define (gnc:options-run-callbacks options)
|
|
((options 'run-callbacks)))
|
|
|
|
(define (gnc:options-set-default-section options section-name)
|
|
((options 'set-default-section) section-name))
|
|
|
|
(define (gnc:options-get-default-section options)
|
|
((options 'get-default-section)))
|
|
|
|
;; Copies all values from src-options to dest-options, that is, it
|
|
;; copies the values of all options from src which exist in dest to
|
|
;; there.
|
|
(define (gnc:options-copy-values src-options dest-options)
|
|
(if
|
|
dest-options
|
|
(gnc:options-for-each
|
|
(lambda (src-option)
|
|
(let ((dest-option (gnc:lookup-option dest-options
|
|
(gnc:option-section src-option)
|
|
(gnc:option-name src-option))))
|
|
(if dest-option
|
|
(gnc:option-set-value dest-option
|
|
(gnc:option-value src-option)))))
|
|
src-options)))
|
|
|
|
(define (gnc:send-options db_handle options)
|
|
(gnc:options-for-each
|
|
(lambda (option)
|
|
(gnc-option-db-register-option db_handle option))
|
|
options))
|
|
|
|
(define (gnc:options-make-end-date! options pagename optname sort-tag info)
|
|
(gnc:register-option
|
|
options
|
|
(gnc:make-date-option
|
|
pagename optname
|
|
sort-tag info
|
|
(lambda ()
|
|
(cons 'relative 'end-accounting-period))
|
|
#f 'both
|
|
'(
|
|
today
|
|
end-this-month
|
|
end-prev-month
|
|
end-current-quarter
|
|
end-prev-quarter
|
|
end-cal-year
|
|
end-prev-year
|
|
end-accounting-period
|
|
))))
|
|
|
|
(define (gnc:options-make-date-interval! options pagename name-from info-from
|
|
name-to info-to sort-tag)
|
|
(gnc:register-option
|
|
options
|
|
(gnc:make-date-option
|
|
pagename name-from
|
|
(string-append sort-tag "a") info-from
|
|
(lambda () (cons 'relative 'start-accounting-period))
|
|
#f 'both
|
|
'(
|
|
today
|
|
start-this-month
|
|
start-prev-month
|
|
start-current-quarter
|
|
start-prev-quarter
|
|
start-cal-year
|
|
start-prev-year
|
|
start-accounting-period
|
|
)))
|
|
(gnc:options-make-end-date! options pagename name-to
|
|
(string-append sort-tag "b") info-to))
|
|
|
|
(define (gnc:option-make-internal! options section name)
|
|
;; this function will hide the option specified
|
|
;; the option functionality is unchanged
|
|
(let ((opt (gnc:lookup-option options section name)))
|
|
(if opt
|
|
(vector-set! opt 3 'internal)
|
|
(gnc:error "gnc:option-make-internal! cannot find " section " / " name))))
|