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
- Introduction
- Getting Started
- General
- Configuration
- Charts
- Axes
- Developers
- Popular Extensions
- Samples
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_depson the appropriate line ofjhbuildrc-custom. - If you are running a newer version of macOS than the Github actions virtual environment change the
setup_SDK()line at the bottom ofjhbuildrc-customtosetup_SDK('11'), substituting the VM's macOS version for '11'. - Create the directory
/Users/runner/and make yourself the owner:Substituting your own userid for 'me'.textsudo mkdir /Users/runner sudo chown me /Users/runner mkdir /Users/runner/gnucash - Run
util/ci/macos-ci-deps/make-macos-deps-tarball.sh gnucash-4.2-mac-dependencies.tar.xzfrom 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)
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
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
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
rendered in sequence when you call (gnc:html-document-render) at the
end of your report. You can think of one
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 anobject 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 thebody .You can also markup using ANY tag with (gnc:html-markup tag
. body), which does the expectedbody 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 1Each 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 theand . The markup style associates
a tag name with anstructure, 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))- the HTML tag to render (specified by 'tag). Note that this
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, anrecord 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. Everyhas 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 HereIt 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 ancreated 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:
/* 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:
Start with version information of `0:0:0' for each libtool library.
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.If the library source code has changed at all since the last
update, then increment REVISION (C:R:A' becomesC:r+1:A').If any interfaces have been added, removed, or changed since the
last update, increment CURRENT, and set REVISION to 0.If any interfaces have been added since the last public release,
then increment AGE.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
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 ---
- Files Extracted: 8
- Estimated Token Budget: ~7836 tokens
- Canonical Reference: https://codewiki.google/github.com/Gnucash/gnucash