Register module outside

Linas Vepstas linas@linas.org
Thu, 15 Nov 2001 10:50:47 -0600


On Thu, Nov 15, 2001 at 12:01:08AM -0800, Ivan Suchy was heard to remark:
> Hello, gnucash team.
> 
> In "Architectural overview" you are writing that
> " The register code is completely independent of the engine 
> code, 
> knows nothing about accounting or any of the other GnuCash 
> subsystems. 
> It can be used in independent projects that have nothing to 
> do with accounting. "

That, at least, is the theory.  In practice, you will be the 
first victim^H^H^H^H^H^H user other than gnucash.

> PLEASE could you help me and say me exactly which source 
> files I need, to use register in my own GTK application?
> Is it whole src/register directory or only 
> src/register/register-core dir? Need I files from other 
> directories in
> gnucash source.

The contents of src/register/register-core are 'gui-independent';
it used to work with motif as well as gnome.  The motif port is dead.

The contents of  src/register/register-gnome implement the
gnome-specific parts of the register. 

The contents of src/register/ledger-core consists of gnucash code
that puts gnucash data into the register.  It should probably be
moved to src/ledger or something like that.

The 'programming interface' for the register is given in the *.h 
files of  src/register/register-core.  You should *not* invoke any 
of the routines in src/register/register-gnome directly from your code.

The documentation for teh programming API is in 
src/doc/design/register.texinfo

unfortunately, the new documentation is not as clear as the old docs,
which I will try to fix. In the meanwhile, here are the old docs:

> Thank you very much for your answer.

What do you plan to use this for?

> 
> Sincerely,
> 
> Ivan Suchy

-- 
pub  1024D/01045933 2001-02-01 Linas Vepstas (Labas!) <linas@linas.org>
PGP Key fingerprint = 8305 2521 6000 0B5E 8984  3F54 64A9 9A82 0104 5933


The Register Object
-------------------
The register is an infrastructure for building 
a modular spread-sheet/matrix/array of cells,
where each cell may have a unique/special 
capability, e.g. to understand only dates, amounts
or text.  The register has been designed to 
be easy to extend, modular & easy to maintain,
and memory-efficient.  It is intended to be used
for building financial apps and spread-sheets.

Features
--------
-- Supported cell types:
   Date:        display and/or edit of date, can 
                use accelerator keys to set date
   Price/Value: display and or edit of numeric quantity
   Text:        arbitrary text string display and/or edit
   Quickfill:   auto-completes user's typed in entry
                to match previous entries
   Combo:       pull-down menu of choices
   Recncell:    checkbox, click to cycle through values

-- Modular: cells are their own objects, new cells can 
                be invented.
-- Configurable: layout of cells is programatically 
                modifiable.
-- Tabular: cells are handled in groups ("blocks")
                that can be manipulated as a whole.
-- Multi-tabular: multiple cell-blocks can be defined
                for one table, allowing different sets
                of rows to have distinct layouts
-- Tab-Groups:  Tabbing order between cells is customizable
-- Engine-Independent: No assumptions made about source of 
                data, no predefined financial structure 
                required or enforced.
-- Transaction Support: Groups of cells can be treated
                as a single transactional entity, allowing
                all edits to be committed or rejected as
                a whole.
-- C language implementation.
-- Identical function available via Motif or GTK.  The GUI 
                code segregated, theoretically making port to 
                Qt easy.


Philosophy
---------
The register object, indeed, all code in this directory, does not
depend on (should not depend on) any code in the accounting engine,
or on any code in the main application.  It should be possible to use 
the register in a stand-alone fashion.   As a result of this 
"independence" philosophy, there is a very small amount of
duplicated code for date handling (i.e. there are similar functions
in src/register/datecell.c and src/engine/date.c).  As cleanup
continues, this duplication will disappear.


Design Overview
---------------
The register is built of several components:
the "cell", the "cellblock", the "cursor", the 
"table", and the "register".

Cell
----
The "cell" is an active cell object.  This object
defines callbacks that are called when the user
enters the cell (e.g. by mouse-clicking on a cell in a 
table, or tabbing to it), when the user attempts to 
modify text in the cell (e.g. by typing in it), and 
when the user leaves the cell (e.g. by mouse-clicking
elsewhere, or tabbing away).

Special-purpose cells can be created by "inheriting"
from the cell object.  Thus, there are special-purpose
cells for handling dates, pull-down menus, text fields,
monetary amounts, etc.

Cells implementations may or may not contain GUI
code.  Cells which require only that text be displayed
are completely "GUI-independent"; that is, they
depend on the underlying table to display the text.
Cells which require additional GUI elements (e.g.
pull-down menus) must implement the proper GUI
handling on their own (using e.g. Motif, GTK or Qt).

Cellblock
---------
The "cellblock" is an array of active cells.  The
cells are laid out in row-column order.  The 
cellblock serves as a convenient container for
organizing active cells in an array.   It provides
several functions. First, it defines a tab-group 
(group of cells that can be traversed by hitting 
the tab-key).  More importantly, through the mechanism
of "cursors" (defined below),  it allows a group
of cells to be treated as a single transactional entity.
That is, the cursor/cellblock allows all edits to
a groups of cells to be simultaneously committed
or rejected by underlying engines.  This makes
it appropriate for use as a GUI to transaction-processing
applications with two-phase commit requirements.

Table
-----
The "table" is the displayed matrix.  The table is
a complex object; it is NOT merely a cellblock.
The table provides all of the GUI infrastructure for
displaying a row-column matrix of strings. 

The table provides one very important function
for minimizing memory usage for large matrixes.
It defines the notion of a "cursor".  The "cursor"
is a cellblock (an array of active cells) that is
moved to the location that the user is currently
editing.  The cursor "virtualizes" cell functions;
that is, it makes it seem to the user as if all
cells in the table are active, when in fact the only
cell that actually needs to be active is the one that 
the user is currently editing.  

The current table design allows multiple cursors 
to be defined.  When a user enters a cell, the appropriate
cursor is positioned within the table.  Cursors
cannot overlap: any given cell can be mapped to at most
one cursor.   Multiple-cursor support allows tables
to be designed that have a non-uniform layout.  
For example, the multiple-cursor support can be
used to define a tree structure of headings/topics and 
sub-headings/sub-topics, where the layout/format of 
the heading is different from the sub-headings.
A financial example is a table which lists splits
underneath their parent transaction.  This is 
very different from a checkbook register, where
all entries are uniform, and can be handled with
a single repeated cursor.

Register
--------
The register is a special-purpose object aimed at
the display of financial transactions.  It includes
cells for the date, prices, balances, transfer accounts,
etc.  The register is where the cells, cursor and
table get put together into a unified whole.  The
register defines specific, actual layouts and widths
of the date, price, etc. cells in a table.  It includes 
a table header, and defines more than ten specific layouts:
bank, credit-card, stock, general ledger, etc.



Portability Notes
-----------------
The register should be easily portable to Qt.  Most of 
the files contain no Motif or GTK code, and thus do not 
require any porting.  All Motif-specific code appears in 
the file "table-motif.c" and "combocell.c".  All that 
table-motif.c does is to set up the XbaeMatrix Motif widget,
and to install callbacks for cell enter/modify/leave.  
The combocell.c file defines a pull-down menu that can be 
inserted into Xbae cells.

Porting hints: stub out combocell.c, and work on table-motif.c 
first.

> Could you give me a (brief) overview of what's going on in
> table-motif.  i.e. what's the top-level widget etc. (it looks like
> most of the functionality is provided by the XbaeMatrix which doesn't
> have a direct GTK correspondent...), and how do the parts of that
> widget that you use behave?
>
> For example, I might say "GTK's CList allows you to set up a 2d table
> where each cell contains a text field, a pixmap, or both..."  That's
> the level of description I'm thinking of for the stuff you use from
> Xbae, since I don't know anything about it.

XbaeMatrix is "just" a table widget: it provides the following:

-- each cell is a "virtual" text widget.  (there is really only one text
   widget in Xbae, it gets dynamically mapped to the currently active
   cell.  This is all 100% transparent both to programmer and user.
   I only mention this because it makes Xbae very efficient space and
   speed wise for large tables.)
-- cells can contain pixmaps
-- cells can contain widgets (although this is kind of a hack --
   I hacked this code in myself. Xbae internals are very complex).
-- cells deliver enter and leave callbacks when user enters
   or leaves with mouse/tab key/arrow key.   programmer is allowed
   to change text upon enter/leave.
-- cells deliver modify callback.  modify callback presents old and new
   data as typed by the user.  callback allows programmer to accept or
   reject the edits.  (e.g. I use this to accept only number &
   punctuation in money cells, and only valid dates in date cells.
   I also use this to implement accelerator keys for the date cells.)
-- allows cells to be marked read-only (not modifiable by user).
-- allows a fixed number of rows & cols on left, right, bottom, top.
   (I only fix top rows).
-- automatically puts up scroll bar on the scrolling region, when
   the scrolling region is larger than physical window.
-- user-defined data can be anchored to each cell, and/or row,
   and/or column.
-- allows variety of highlighting features. (not used).
-- allows tab-traversal order to be set (which cells are visited
   when tab key/arrows keys are hit).
-- allows rows/columns to be labeled (not used).

If you look at table-motif.c, you will see the following structure:

xaccCreateTable() initializes the table widget
cellCB () callback that is called when user enters/leaves a cell,
    (by clicking on it with mouse, or with tab/arrow keys), or
    when user attempts to edit the cell.  This callback in turn calls
    the enterCB(), leaveCB() and modifyCB() routines, which then call
    GUI-independent callbacks for the register cell handlers.
    Depending on the result of the cell callbacks, the string
    stored in the cell is modified or not.
traverseCB() callback that is called when user tabs through sequence of
    cells.  This callback allows a sequence of cells to be defined
    for tabbing through.

Under the covers, XbaeMatrix uses the Motif Text Widget to create
"cooked" strings out of raw key/button presses.  The Motif Text
Widget automatically handles French/German/Icelandic/Cyrillic keyboards,
it handles the shift, alt & delete keys automatically, it handles
the delete/backspace keys automatically, it handles middle-mouse
paste automatically, etc.  The resulting "cooked" strings are passed
to the register code (in table-motif.c) which then hands it off to the
cell handlers.

People porting this should give serious thought to finding and using
"vi" or "emacs" editing text widgets under the covers. 

That's pretty much it, except for some assorted GUI-independent setup.



Apologies
---------
This is not the world's most elegant design, its 
occasionally a bit of a hack, occasionally over-complex,
but it more or less works, and should be quite extensible.
Its certainly light-years ahead of its predecessor.

-- Linas Vepstas
-- March 1998