gnucash Documentation

GnuCash Double-Entry Accounting Program.

4,380 stars C C 8 files ยท ~7,914 tokens
RAW Doc

Technical Documentation: Gnucash/gnucash

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`.github/workflows/README.md`)

Github Actions Continuous Integration Testing Workflows.

ci-tests.yml runs Ubuntu 18.04 and Ubuntu 20.04 using Github-provided virtual environments. The virtual environments are about twice as fast as Docker ones and getting Docker to run Ubuntu images was problematic. Note that updating Ubuntu 18.04 updates ICU4C from v60 to v65 and that causes conflicts with Boost, so don't.

ci-docker.yml runs tests in a Docker container running Arch Linux.

mac-tests.yml runs tests on macOS using a Github-provided virtual machine. Note that this test relies on a prebuilt tarball containing all of the dependencies. Instructions for building that tarball along with some support scripts may be found in utils/ci/macos-ci-deps.


Overview (`borrowed/chartjs-2/README.md`)

Documentation

Contributing

Instructions on building and testing Chart.js can be found in the documentation. Before submitting an issue or a pull request, please take a moment to look over the contributing guidelines first. For support, please post questions on Stack Overflow with the chartjs tag.

License

Chart.js is available under the MIT license.


Overview (`util/ci/macos-ci-deps/README.md`)

For creating the macOS dependency tarball required by the Github CI tests.

Requirements:

  • Administrator privs on your Mac.
  • Project admin privs for https://sourceforge.net/projects/gnucash.
  • Jhbuild doesn't cross-compile well so you need a mac with the same architecture as the github VM. Check here for the current configuration. At the time of this writing it's x86_64.
  • Xcode or command-line tools (install the latter with sudo xcode-select -install).
    To build this tarball you must be running the same or newer macOS version as the Github VM.

Procedure:

  • Set up a Gtk-OSX build environment following the GnuCash Quartz Build instructions.
  • Retrieve jhbuildrc-custom and put it in ~/.config.
  • Set modules = _modules_deps on the appropriate line of jhbuildrc-custom.
  • If you are running a newer version of macOS than the Github actions virtual environment change the setup_SDK() line at the bottom of jhbuildrc-custom to setup_SDK('11'), substituting the VM's macOS version for '11'.
  • Create the directory /Users/runner/ and make yourself the owner:
    text
    sudo mkdir /Users/runner
    sudo chown me /Users/runner
    mkdir /Users/runner/gnucash
    Substituting your own userid for 'me'.
  • Run util/ci/macos-ci-deps/make-macos-deps-tarball.sh gnucash-4.2-mac-dependencies.tar.xz from the root of the source directory, changing the tarball's name if appropriate.
  • Upload the resulting tarball to the Dependencies folder in the Gnucash files section on SourceForge.
  • If necessary modify `.github/workflows/mac-tests.yaml to reflect the tarball's URI.

Doc CMakeLists (`doc/CMakeLists.txt`)

add_subdirectory(examples)

set(doc_DATA
gtk-3.0.css
)

set(doc_noinst_DATA
CMakeLists.txt gnucash.1.in
gnucash-cli.1.in tip_of_the_day.list.c README.txt)

install(FILES ${doc_DATA} DESTINATION ${CMAKE_INSTALL_DOCDIR})

set_local_dist(doc_DIST_local ${doc_DATA} ${doc_noinst_DATA})
set(doc_DIST ${doc_DIST_local} ${examples_DIST} PARENT_SCOPE)

foreach(doc_file ${doc_DATA})
configure_file(${doc_file} ${DATADIR_BUILD}/doc/gnucash/${doc_file} COPYONLY)
endforeach()

Generate the tip of the day file.

set (totd "tip_of_the_day.list")
add_custom_command(OUTPUT ${DATADIR_BUILD}/gnucash/${totd}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${totd}.c
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND}
-D SRC=${CMAKE_CURRENT_SOURCE_DIR}/${totd}.c
-D TOTD=${totd}
-D DST_DIR=${DATADIR_BUILD}/gnucash
-D CMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-P ${CMAKE_SOURCE_DIR}/cmake/configure-totd.cmake
)
add_custom_target(totd ALL DEPENDS ${DATADIR_BUILD}/gnucash/${totd})

install(FILES ${DATADIR_BUILD}/gnucash/tip_of_the_day.list DESTINATION ${CMAKE_INSTALL_DATADIR}/gnucash)

Generate manpages.

foreach (manpage gnucash gnucash-cli)
add_custom_command(OUTPUT ${DATADIR_BUILD}/gnucash/${manpage}.1
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.1.in gnc-vcs-info
COMMAND ${CMAKE_COMMAND}
-D SRC=${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.1.in
-D DST=${manpage}.1
-D VCS_INFO_FILE=${VCS_INFO_FILE}
-D DATADIR_BUILD=${DATADIR_BUILD}
-D SRC_DIR=${CMAKE_SOURCE_DIR}
-P ${CMAKE_SOURCE_DIR}/cmake/configure-manpage.cmake
)
add_custom_target(${manpage}-manpage ALL DEPENDS ${DATADIR_BUILD}/gnucash/${manpage}.1)

text
install(FILES ${DATADIR_BUILD}/gnucash/${manpage}.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)

endforeach()


Doc README (`doc/README.txt`)

This directory contains manpages, the tip-of-the-day message
source, and a sample gtk-3.0.css to demonstrate how to customize
GnuCash's Graphical User Interface.

The example directory contains some basic files for
elementary testing and to illustrate the formats.


Doc Examples CMakeLists (`doc/examples/CMakeLists.txt`)

set(examples_DATA
Money95bank_fr.qif
Money95invst_fr.qif
Money95mfunds_fr.qif
Money95stocks_fr.qif
README
README_invoice
abc-all.qif
abc.qif
bogus.qif
cbb-export.qif
currency_tree_xml.gnucash
every.qif
invoice.csv
ms-money.qif
quicktest.qif
swipe.qif
taxreport.gnucash
web.qif
)

install(FILES ${examples_DATA} DESTINATION ${CMAKE_INSTALL_DOCDIR})

set_dist_list(examples_DIST ${examples_DATA} CMakeLists.txt )


Gnucash Report Doc Report Html (`gnucash/report/doc/report-html.txt`)

Notes on the new HTML generation infrastructure.

It's been time to fix the current HTML infrastructure for a while.
Pretty much every report reinvents any wheel it happens to need for
generating HTML markup and for the most part the reports are brutally
brittle; since they consist of literal HTML strings embedded in Scheme
code, you will have a very hard time customizing the way they look or
what they do.

I am mostly done with a completely new system for generating HTML in
reports. It's not terribly complicated or sophisticated but it does
have some nice features, including support for CSS-like "styles" for
markup that can by changed on the fly and a "style sheet" template
mechanism that creates a new kind of entity, the style sheet, that can
influence the overall appearance and style of any report which uses
it. This will allow folks to create custom style sheets which make
all of their reports share a common look and feel, without having to
modify the reports.

My goal is to make reports much shorter and cleaner, trying to leave
all the fancy formatting stuff to the style sheets, and to make it
possible to make reports both arbitrarily good-looking and similar to
each other. That will make it easier to use reports in different
contexts (printed formal statements vs. short tables embedded in a
big window with other short statements) and will make it easier for
people to scavenge other people's reports for code to make new
reports.

I would like report writers and other interested parties to have a look
at this document and the bits of sample code in it and let me know if
this looks reasonable.

By convention, I name all Guile "record types" with surrounding <>.
So is the "class object" for the
record type. I will probably use "method" and "class" a lot even
though it's not a proper object system. You know what I mean.

Thanks,
b.g.

========================================================

At the top level, each report should create exactly one object of type
. The is the "container" for all your
report HTML information. You can render it to an HTML string with
(gnc:html-document-render) or add some content to it with
(gnc:html-document-add-object!).

An is basically a set of that get
rendered in sequence when you call (gnc:html-document-render) at the
end of your report. You can think of one as a
block-level element in HTML, like a paragraph, a table, or a guppi
graph. There are several different types:

  • text. You can stick as much marked up text as you want in one
    text object; you can limit an object to one paragraph
    or stick multiple paragraphs in it.

    In order to preserve style information, you shouldn't use direct
    literal markup in your strings (though it doesn't really hurt
    anything, it is not seen by the style system so you can't
    influence the way tags are rendered after the fact). There is a
    family of functions called gnc:html-markup-* that are shortcuts
    to most of the common HTML markup (, , ,

    -

    ).
    The markup functions can be composed and take any number of
    arguments; the arguments are rendered and concatenated to become
    the body of the body.

    You can also markup using ANY tag with (gnc:html-markup tag
    . body), which does the expected body by default (or
    something else entirely if you have the "tag" style set
    differently... more later) or (gnc:html-markup/attr tag attr
    . body), which puts the attribute string 'attr' inside the start
    tag: body. If there are attributes for the tag
    specified as part of the current style, the attributes you
    specify will be appended to the style's attributes.

    gnc:html-markup puts an end tag after the body; you should use
    gnc:html-markup/no-end and gnc:html-markup/attr/no-end if you
    wish to force no end tag. Don't do this unless HTML syntax
    forbids end tags, please.

    Here is a short but complete HTML document demonstrating how to
    create and render text:

    (let ((doc (gnc:make-html-document))
    (txt (gnc:make-html-text)))

    (gnc:html-text-append! txt
    (gnc:html-markup-h2 "This is a header")

    (gnc:html-markup-p
    "This is a paragraph of plain text with a "

    (gnc:html-markup-b "bold")
    " section in the middle."))

    (gnc:html-document-add-object! doc txt)
    (gnc:html-document-render doc))

    html-document-render returns a string:

    "

    This is a header

    This is a paragraph of plain text with a **bold** section in the middle. "

    Any literals, like strings or numbers, that you include in an
    html-text object get rendered according to the
    in effect for their type, so please don't render them yourself
    (unless you really want to).

    See the section for more info, but as a rule of
    thumb strings will be interpreted literally with HTML special
    characters escaped for you (i.e. you don't need to put > in
    the string, go ahead and put >), but if you want to translate to
    gibberish on the fly or write a stylesheet to render strings in
    tables as all caps you can do that too.

  • tables. You can add data by rows or columns to an
    and set row and column headers. You can set row and column
    styles for tags and data, and even individual cell styles if you
    want, so you can have pretty good control over how numbers and
    rows are rendered even if you just add a column of numbers as
    numbers. If you need to get and set the contents of individual
    cells, you can do that too; the table is automatically grown to
    whatever dimensions you need.

    A simple example, taken from the account-summary report:

    text
    (let ((table (gnc:make-html-table)))
        ;; column 1: account names (just strings)
        (gnc:html-table-append-column!
         table
         (map (lambda (acct)
                (let ((name (gnc:account-get-name acct)))
                  (gnc:make-html-text
                   (gnc:html-markup-anchor
                    (string-append "gnc-register:account=" name)
                    (gnc:account-get-name acct)))))
              accounts))
        
        ;; column 2: balances 
        (gnc:html-table-append-column!
         table
         (map (lambda (acct)
                (gnc:account-get-balance acct))
              accounts))
    
        ;; column headers 
        (gnc:html-table-set-column-headers!
         table
         (list (_ "Account name") (_ "Balance")))
        (gnc:html-document-add-object! doc table))

    The 'html-markup-anchor' bit just makes each account name into an
    anchor that opens the appropriate register, like

    [My Bank Account](gnc-register:account=My Bank Account)

    The contents of a cell can be any type of data or any
    . There's a special kind of that's
    only useful in tables: the . You want to use
    this if you need to specify a rowspan or colspan that is not 1;
    table cells have methods to set the rowspan and colspan.

  • pie charts. Pie charts are simple affairs. They have data (a
    list of numbers), a title and subtitle, a list of colors and a
    list of labels. Colors and labels are matched to data points in
    order.

  • bar charts. Bar charts have "rows" and "columns" of data, where
    the value of a data point determines the height of the bar and
    you generally want more rows than columns:

    X X Y
    X Y X Y X : Column 0
    X Y X Y Y : Column 1
    X Y X Y
    X Y X Y
    r0c0 r0c1 r1c0 r1c1
    Row 0 Row 1

    Each column has a distinct color (gnc:html-bar-chart-set-column-colors!)
    and there's a legend that associates column colors with column labels.
    Row labels are printed under row groupings.

  • scatter charts. There's a vector of "X", and a vector of "Y", of
    the same length; a marker-style; a marker color; X label; and Y
    label.

Styles

We have three different kinds of style control information available:

  • markup styles, embodied by the class.
    Whenever ANY HTML tag is rendered, a markup style is looked up
    starting from the most local context and working back to the
    and . The markup style associates
    a tag name with an structure, which has
    the following fields:

    • the HTML tag to render (specified by 'tag). Note that this
      may be different from the tag used to look up the style (the
      one passed to html-markup). (See NB below.)
    • Any attributes to be used inside the start tag (listed
      individually as 'attribute (list name value))
    • The font face to use in the body ('font-face)
    • The font size to use ('font-size)
    • The font color ('font-color)

    These properties are merged hierarchically, with the child (most
    local context) taking precedence. For all fields except the
    'attributes', it's a "child-take-all" strategy, i.e. the child's
    style completely overrides the parent's. For 'attributes', as long as
    the child does not explicitly specify a new HTML tag the attributes are
    merged with the parent's, with the child's style winning if both
    parent and child specify values for the same attribute.

    Each type of is responsible for creating its own
    "local style context" and representing local style info, so to set
    the style for (for example) an HTML text object, you call
    (gnc:html-text-set-style! obj "tag" style-info).

    The style-info for any html-object is a bunch of field-value pairs:

    ;; render all bold text as big and green as well as bold
    (gnc:html-text-set-style! my-txt "b"
    'font-color "00ff00" 'font-size 7)

    ;; make sure all table cells are aligned right
    (gnc:html-table-set-style! my-table "td"
    'attribute '("align" "right"))

    You can use ANY string as a markup tag, not just legit HTML ones.
    By default, the HTML tag used is the same as the markup tag
    (which is why the examples above don't specify a 'tag in the
    style info.. it's OK to do so but redundant) but if you pass
    another tag it's used instead; 'tag "" means use no tag at all.

    So here's how to make text marked up with the tag "bigred" be big
    and red:

    (let ((doc (gnc:make-html-document))
    (txt (gnc:make-html-text)))

    ;; add some text with bigred markup to the
    ;; text object
    (gnc:html-text-append! txt
    (gnc:html-markup "bigred"
    (gnc:html-markup-p
    "This is big red text.")
    (gnc:html-markup-p
    (gnc:html-markup-b
    "This is big red BOLD text."))))

    ;; set the style for bigred text .. it doesn't have to
    ;; be before bigred markup is used, just before the
    ;; object is rendered.
    (gnc:html-text-set-style! txt
    "bigred" 'tag "" 'font-color "ff0000" 'font-size 7)
    ;; ^^ NB: "bigred" is the tag. 'tag "" is the info in the style table.

    (gnc:html-document-add-object! doc txt)
    (gnc:html-document-render doc))

text
This will render to 

 <html><head></head>
 
 
 This is big red text.
 **This is big red BOLD text**
 
 </html>
  • data styles, embodied by the class.
    Whenever a rendering function needs to render a literal piece of
    Scheme data, it invokes the data style to figure out how. As of
    this writing, an record just contains a
    function which knows how to render a particular type of data, but
    this may change in the future.

    Data styles and markup styles are both set through the
    "-set-style" methods for various classes, with the difference
    being that the type name is the key (i.e. "")
    instead of the HTML tag name. For built-in Scheme types, there
    are special cases: "", "", and "" are
    defined. Since angle brackets aren't legal in HTML tags, there's
    no namespace conflict; if your record type names (as returned by
    (record-type-name (record-type-descriptor obj)) don't start and
    end with angle brackets they will be added for setting and
    getting data style information. You shouldn't have to worry about
    this.

  • "style sheets", embodied by the class. They
    are more like templates than CSS stylesheets. Every
    has a stylesheet, and that stylesheet controls
    the HTML "frame" that the document is rendered into, as well as
    setting up the highest level of markup styles and data styles for
    rendering the document.

    Every report now automatically has a "Stylesheet" option in the
    "General" section which allows a stylesheet to be selected. At
    the moment, the list of available stylesheets is fixed when the
    report is created; this is a bug but I'm not sure how to fix it.

    The default stylesheet (if none is specified in the report) puts
    the trivial HTML frame around your 's
    s:

    Your Title Here Your Objects Rendered Here

    It has some basic options for setting the background color, table
    formatting, background pixmap, and so on.

    Other stylesheets haven't been written as of this writing, but
    may put your objects in a cell of an HTML table with a fancy logo
    in the top right, the document title in a "prepared for" section
    with a date, letterhead or other graphics in the background, and
    so on. Some or all of this should be customized in the style
    sheet's parameter editor, which uses the same framework as the
    report parameters editor and the Gnucash preferences editor.

    Creating stylesheets:

    You can create your own style sheets through the
    gnc:define-html-style-sheet function. Defining a style sheet is
    much like defining a report: you need an 'options' object and a
    'renderer' function, plus a style-sheet version and name.

    Since the stylesheet is really defining a complete HTML document
    itself, you should use an created locally in the
    stylesheet renderer to handle all the rendering. Just use the
    default stylesheet for that document so you don't get off into
    recursive meta-style land. It will DTRT. As you are creating
    the document, grab the appropriate objects and styles from the
    user document (the one you are writing a style sheet for, which
    is passed as an argument to the renderer) and stuff them in the
    local html-document.

    This sounds more confusing than it actually is. Here's a very
    simple style sheet that provides a configurable background color
    for any report that uses it. Of course you could just add a bg
    color as an option to every report; the advantage of doing it
    here is that when you change the bgcolor in the stylesheet
    options editor, it changes it in every report that uses that
    style sheet.

    There's a new "Style Sheet Dialog" in gnucash that lets you copy
    and modify existing stylesheets from the GUI, so you can take a
    distributed stylesheet, copy it with a new name, and change the
    parameters to customize it.

    (let ()
    (define sample-options
    (let ((options (gnc-new-optiondb)))
    (gnc-register-color-option options
    (_ "Style Sheet Options")
    (_ "Background Color") "a" (_ "Background color for reports.")
    "ffffff")
    options))

    (define (sample-renderer options doc)
    (let ((ssdoc (gnc:make-html-document))
    (bgcolor
    (gnc:color->html
    (gnc-optiondb-lookup-value options
    (_ "Style Sheet Options")
    (_ "Background Color")))))

    ;; this says that the HTML tag should have
    ;; the attributes bgcolor=COLOR, so it will get
    ;; rendered like
    (gnc:html-document-set-style!
    ssdoc "body" 'attributes
    (with-output-to-string
    (lambda ()
    (display "bgcolor=")
    (display bgcolor))))

    ;; if you want to set default markup and data styles for
    ;; documents using this stylesheet, do it here. This
    ;; style element doesn't do anything, it's just there
    ;; as an example:
    (gnc:html-document-set-style! ssdoc "p" 'tag "p")

    ;; grab the markup and data styles and objects out of the
    ;; document... you have to do this in every style sheet!
    (gnc:html-document-push-style
    ssdoc (gnc:html-document-style doc))
    (gnc:html-document-append-objects!
    ssdoc (gnc:html-document-objects doc))

    ;; render the ssdocument (using the trivial stylesheet).

    ;; since the objects from 'doc' are now in ssdoc, this
    ;; renders the whole package.
    (gnc:html-document-render ssdoc)))

    (gnc:define-html-style-sheet
    'version 1
    'name "Sample Style Sheet"
    'renderer sample-renderer
    'options sample-options))


Libgnucash Gnc Module Doc Design (`libgnucash/gnc-module/doc/design.txt`)

What is a Gnucash module?

A gnucash module is a dynamically loadable libtool library that
defines the following symbols:

text
/* what version of the module system interface is assumed */
int  gnc_module_system_interface;

/* information about the module's version */ 
int  gnc_module_current;
int  gnc_module_revision;
int  gnc_module_age; 

/* init is called each time a module is loaded; 
 * 'refcount' is 0 the first time the module is loaded. */ 
int  gnc_module_init(int refcount);
 
/* end is called each time the module is unloaded, if present.  
 * 'refcount' is 0 the last time the module is unloaded. */
void gnc_module_end(int refcount);  

/* descriptive information */ 
char  * gnc_module_path(void);
char  * gnc_module_description(void);

gnc_module_system_interface is the revision number of the interface
listed above (i.e. the names and type signatures of the symbols each
module must define). The current revision number is 0; all modules
should assign gnc_module_system_interface = 0. As the interface
evolves, this should allow us to continue to load older modules.

The current, revision, age triplet describe the module version
according to libtool(1) conventions. To quote from the libtool info
pages:

  1. Start with version information of `0:0:0' for each libtool library.

  2. Update the version information only immediately before a public
    release of your software. More frequent updates are unnecessary,
    and only guarantee that the current interface number gets larger
    faster.

  3. If the library source code has changed at all since the last
    update, then increment REVISION (C:R:A' becomes C:r+1:A').

  4. If any interfaces have been added, removed, or changed since the
    last update, increment CURRENT, and set REVISION to 0.

  5. If any interfaces have been added since the last public release,
    then increment AGE.

  6. If any interfaces have been removed since the last public release,
    then set AGE to 0.

gnc_module_path should return a newly-allocated string containing the
"module path". The module path is a logical path with elements
separated by /. The path will be used to structure views of available
modules so that similar modules can be grouped together; it may or may
not actually correspond to a filesystem path. The last element of the
module path is the name of this module. For example,
char * path = "gnucash/core/engine";
defines the "engine" module, which is in the gnucash/core group of
modules.

gnc_module_description should return a newly-allocated 1-line
description of what the module does. This can be displayed by GUI
elements to allow users to select modules to load.

While the module system used to have wrappers for scheme access
this functionality is now deprecated. Scheme code should no longer
try to use any gnc-module functionality. All C code that is potentially
useful for scheme has been or can be wrapped using swig. That wrapped
code can be made available to scheme code using guile's load-extension
functionality. For convenience, most of this wrapped code is
accompanied by a scheme module that handles the load-extension part for you.
So in most cases simply calling (use-module (gnucash )) will
do the trick.

Initializing the module system

Somewhere at program startup time, you need to call
gnc_module_system_init from C. This scans the
directories in the GNC_MODULE_PATH and builds a database of the
available modules.

You can rebuild the module database at any time (say, if you know a
new module has been installed or the user has changed the module path
via some in-program mechanism) by calling gnc_module_system_refresh.

Loading modules

From C call gnc_module_load(path, interface). This returns a GNCModule
if a qualifying module was successfully loaded, FALSE otherwise.
GNCModule is an opaque type.

A qualifying module is any module whose gnc_module_path matches the
path specification and for whom "interface" falls between
gnc_module_current and (gnc_module_current - gnc_module_age). If
multiple modules qualify, libtool's rules are used to determine which
to load: the larger of gnc_module_interface, gnc_module_age, and
gnc_module_revision take precedence, in that order.

Module initialization/cleanup

Each time a module is loaded, its gnc_module_init function is called
with an integer argument, 'refcount'. The refcount is the number of
times that gnc_module_load has been called on that particular module.
It is 0 the first time gnc_module_load is called on a module.

Any startup/initialization code should be defined in this function.
If this module depends on other modules, put the necessary
gnc_module_load calls in the init function.

If gnc_module_init returns FALSE, the module is immediately unloaded.
Any cleanup must be done within gnc_module_init before returning.

Each time a module is unloaded via gnc_module_unload, its
gnc_module_end function is called with an integer refcount argument.
refcount is 0 if this 'unload' drops the last reference. In this
case, after the gnc_module_end handler is called the library is
dlclose()-ed.


--- METRICS ---