Saving customized reports (was: GNOME 2: MDI or SDI?)

Christian Stimming stimming at
Fri Jun 11 05:09:17 EDT 2004

Wesley Leggette schrieb:
> Since it is impossible to conviently store report setups
> (except by manually backing them up) without keeping them open, I like
> to keep them open. (...)
> Of course, I suppose just adding the ability to save reports, and even
> better groups of reports, would go a long way. To elaborate, you could
> export or bookmark or whatever your custom configurations for reports.
> You could then also group them together and open the whole group at
> once. Very neat.

This is one of the features most regularly asked for. Although a clean 
implementation of that would require additional GUI components and 
probably quite some code and time, I nevertheless came up with an idea 
that might do already:

The options of an opened report are stored in 
~/.gnucash/books/my_book_name as scheme code. The report is restored by 
running this scheme code and calling gnc:report-restore (in 
src/reports/report-system/report.scm) afterwards. How difficult would it 
be to turn these two steps from restoring a report into a new call of 
the gnc:define-report function, hence offering a new report? It would be 
well sufficient to have a manual procedure involving text file 
manipulation, but fully outside gnucash. A step-by-step instruction to 
create your own report would read as follows:

1. In gnucash, open the report. Change the options so that it shows what 
you want. Close gnucash while leaving that report window opened.
2. Open the file ~/.gnucash/books/<your_book_name> with your favorite 
text editor.
3. Find the section entitled ";; options for report <your_report_name>". 
For each of your still-opened reports, there is one such section. If you 
have multiple reports based on the same template, you need to figure out 
which one you want by looking closely at each report's options.
4. Copy the section with the report options into a new text file, e.g. 
"my-report.scm". The section starts with the command "(let ((options 
..." and it ends with the closing parentheses that closes the opening 
parentheses before the "let" command.
5. In "my-report.scm", replace ??? (FIXME: see below) inside your pasted 
section by ???.
7. Save "my-report.scm" in your gnucash scheme directory. If your 
gnucash installation was installed with the prefix /usr, then this is in 
/usr/share/guile-modules/gnucash/reports/ (FIXME: is this correct?)
8. In the file "report-system.scm" that can be found in that very same 
directory (FIXME: is this correct?), append the line

(load-from-path "my-report.scm")

at the very end of that file. This makes gnucash aware of your new 
report file. If your new file contains any errors that gnucash complains 
about, you can always remove this load-from-path command from this file 
and gnucash will load normally again. Watch out: Each time you install a 
new version of gnucash, the file report-system.scm will be overwritten 
and you will have to insert this line again. But all other steps are not 
affected by a new installation of gnucash.

As for the code that needs to be added: For sure, the normal report 
definition has to be done as usual:

   'version 1
   'name "My personalized report about my Income"
   'options-generator ???
   'renderer ???)

The renderer should probably be the very same function that is already 
used in the original report definition file, e.g. accsum-renderer from 
account-summary.scm for the account summary report. It might be 
necessary to add an additional (export accsum-renderer) in that files, 
but I'm not too sure about this. OTOH the options-generator is probably 
the key to implement this customizing of the report:

Usually, the options-generator is a function that returns the 
appropriate options object. In the scheme code from the user's file with 
the saved options, we actually already have that options object 
available. The saved options code ends with the command

   (gnc:restore-report report-id report-type options)

where "options" is precisely the options object as returned by the 
original options-generator, but now changed into our customized 
settings. So all that we need to do is to replace the gnc:restore-report 
command by a gnc:define-report command, where the options-generator now 
is a lambda that directly returns this very customized options object. 
How about this (with a customized account summary as an example):

    'version 1
    'name "My customized account summary"
    'options-generator (lambda() options)
    'renderer accsum-renderer)

To summarize: The full options command before the manual change would 
read like this:

;; options for report "My customized summary"
(let ((options (gnc:report-template-new-options/name "Account Summary")))
   (let ((option (gnc:lookup-option options "General" "Name")))
      ((lambda (option) (if option ((gnc:option-setter option) "My 
customized summary"))) option))
   ;; ... more options ...
   (gnc:restore-report 1234 "Account Summary" options))

After the manual change, the command would read like this:

;; options for report "My customized summary"
(let ((options (gnc:report-template-new-options/name "Account Summary")))
   (let ((option (gnc:lookup-option options "General" "Name")))
      ((lambda (option) (if option ((gnc:option-setter option) "My 
customized summary"))) option))
   ;; ... more options ...
    'version 1
    'name "My customized summary"
    'options-generator (lambda() options)
    'renderer accsum-renderer))

One very last quirk: When defining a new report, the "Report Name" and 
"Stylesheet" options are *always* added by the report system (in 
gnc:report-template-new-options), not by the original options-generator. 
In our case this means that the options object with the customized 
settings already contains these options, although gnc:define-report is 
going to register them again. What is the behaviour of (hash-set! 
section-hash name new-option), if the section-hash already contains an 
element with the key "name"? Does it silently overwrite the existing 
object, does it fail, or does it create a second entry? Pretty much all 
three cases are not what we want. The simplest solution would be to 
register these two options in gnc:report-template-new-options (in 
report.scm) only if they don't exist yet, i.e. change

         (let ((options (generator)))
           (gnc:register-option options stylesheet)
           (gnc:register-option options namer)


	(define (lookup-existing-option options option)
	  (if option
	    (gnc:lookup-options options (gnc:option-section option) 
(gnc:option-name option))
         (let ((options (generator)))
           (if (not (lookup-existing-option options stylesheet))
	    (gnc:register-option options stylesheet))
           (if (not (lookup-existing-option options namer))
             (gnc:register-option options namer))

More information about the gnucash-devel mailing list