Register: Add a lot of doxygen documentation, add/revise some commenting inside functions, and massage a few debugging messages.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17854 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Charles Day 2009-01-29 11:42:39 +00:00
parent 6cc9146e13
commit 90af51c3e3
6 changed files with 252 additions and 120 deletions

View File

@ -1160,7 +1160,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
message = _("This register does not support editing exchange rates.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("No rate cell.");
LEAVE("no rate cell");
return FALSE;
}
@ -1173,7 +1173,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
message = _("This register does not support editing exchange rates.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("Null rate cell.");
LEAVE("null rate cell");
return FALSE;
}
@ -1181,7 +1181,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
exch_rate = gnc_price_cell_get_value (rate_cell);
if (!gnc_numeric_zero_p(exch_rate) && !force_dialog)
{
LEAVE("Rate already non-zero.");
LEAVE("rate already non-zero");
return FALSE;
}
@ -1198,7 +1198,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
"rate.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("Expanded with transaction cursor. Nothing to do.");
LEAVE("expanded with transaction cursor; nothing to do");
return FALSE;
}
@ -1223,7 +1223,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
message = _("The entered account could not be found.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("No xfer account.");
LEAVE("no xfer account");
return FALSE;
}
@ -1247,7 +1247,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
*/
if (!force_dialog)
{
LEAVE("Txn currency and account currency match, and not forcing dialog.");
LEAVE("txn and account currencies match, and not forcing");
return FALSE;
}
@ -1256,7 +1256,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
{
message = _("The two currencies involved equal each other.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
LEAVE("Register is expanded, or osplit == NULL. Not forcing dialog.");
LEAVE("register is expanded or osplit == NULL; not forcing dialog");
return FALSE;
}
@ -1269,7 +1269,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
{
message = _("The two currencies involved equal each other.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
LEAVE("Register commodity == txn commodity. Not forcing dialog.");
LEAVE("reg commodity == txn commodity; not forcing");
return FALSE;
}
}
@ -1319,7 +1319,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
message = _("The split's amount is zero, so no exchange rate is needed.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("Amount is zero. No exchange rate needed.");
LEAVE("amount is zero; no exchange rate needed");
return FALSE;
}
@ -1332,7 +1332,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
!info->rate_reset &&
split != gnc_split_register_get_blank_split (reg))
{
LEAVE("Gain/loss split. No exchange rate needed.");
LEAVE("gain/loss split; no exchange rate needed");
return FALSE;
}
@ -1354,7 +1354,7 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
if (gnc_xfer_dialog_run_exchange_dialog(
xfer, &exch_rate, amount, reg_acc, txn, xfer_com))
{
LEAVE("Leaving rate unchanged.");
LEAVE("leaving rate unchanged");
return TRUE;
}

View File

@ -25,8 +25,9 @@
#include "table-layout.h"
#include "split-register.h"
/** @addtogroup Ledger
@{ */
/** @addtogroup SplitRegister
* @{
*/
/** @file split-register-layout.h
* @brief Create the actual register visual layout
* @author Copyright (C) 1998, 2004 Linas Vepstas <linas@linas.org>
@ -41,7 +42,7 @@
* original intent was that the layout would be fetched from a
* config file that could be tweaked for a specific, non-GnuCash
* application.
*/
*/
/** Generate the split register layout. */
TableLayout * gnc_split_register_layout_new (SplitRegister *reg);

View File

@ -82,6 +82,68 @@ gnc_split_register_load_type_cells (SplitRegister *reg)
gnc_recn_cell_set_flag_order (cell, "IP");
}
/** Add a transaction to the register.
*
* Virtual cells are set up to hold the data, beginning at @a vcell_loc and
* continuing downward in the same virtual column. The first virtual cell
* will be a "leading" cell, followed by a virtual cell for each split of
* transaction @a trans. For example, the "transaction journal" register
* style keeps all the transaction-level data and totals in the leading
* cell, and all split-level data in the cells that follow.
*
* Each of these cells will remember the GUID of the ::Split to which it
* is associated. The leading virtual cell will be assigned the GUID of
* the "anchoring split" specified by @a split.
*
* Optionally an extra, empty virtual cell will be assigned to no split.
* This should not be confused with the "blank split", because this cell is
* not tied to any split at all, not even the "blank split". A null GUID
* is assigned to it.
*
* The caller can find out which virtual row was used for a particular virtual
* cell by using parameters @a find_trans, @a find_split, and @a find_class.
* If a match is found, the row is returned in @a new_split_row. Otherwise,
* @a new_split_row is not changed.
* - To find the virtual cell for a particular split, set @a find_split to
* the target ::Split and @a find_class to ::CURSOR_CLASS_SPLIT.
* - To find the empty row, set @a find_trans equal to @a trans, @a find_split
* to @c NULL, and @a find_class to ::CURSOR_CLASS_SPLIT.
* - The leading virtual cell is always placed in the row specified by
* @a vcell_loc, but this will not be returned in @a new_split_row unless
* @a find_split is set to the anchoring split and @a find_class is not
* ::CURSOR_CLASS_SPLIT.
*
* @param reg a ::SplitRegister
*
* @param trans the transaction to add to the register
*
* @param split a ::Split to use as the "anchoring split" in the "leading"
* virtual cell
*
* @param lead_cursor the cursor to use for the "leading" virtual cell
*
* @param split_cursor the cursor to use in the split rows that follow
*
* @param visible_splits @c TRUE to make the split rows visible, @c FALSE
* otherwise
*
* @param start_primary_color @c TRUE to use the primary color for the
* "leading" row, @c FALSE otherwise
*
* @param add_empty @c TRUE if an empty row should be added, @c FALSE
* otherwise
*
* @param find_trans the transaction parameter for row searching
*
* @param find_split the split parameter for row searching
*
* @param find_class the cursor class parameter for row searching
*
* @param new_split_row a pointer to be filled with the matching virtual row.
*
* @param vcell_loc the location to begin setting virtual cells. The row
* will be changed to the row below the last row filled.
*/
static void
gnc_split_register_add_transaction (SplitRegister *reg,
Transaction *trans,
@ -90,7 +152,7 @@ gnc_split_register_add_transaction (SplitRegister *reg,
CellBlock *split_cursor,
gboolean visible_splits,
gboolean start_primary_color,
gboolean add_blank,
gboolean add_empty,
Transaction *find_trans,
Split *find_split,
CursorClass find_class,
@ -102,10 +164,13 @@ gnc_split_register_add_transaction (SplitRegister *reg,
if (split == find_split)
*new_split_row = vcell_loc->virt_row;
/* Set the "leading" virtual cell. */
gnc_table_set_vcell (reg->table, lead_cursor, xaccSplitGetGUID (split),
TRUE, start_primary_color, *vcell_loc);
vcell_loc->virt_row++;
/* Continue setting up virtual cells in a column, using a row for each
* split in the transaction. */
for (node = xaccTransGetSplitList (trans); node; node = node->next) {
Split *secondary = node->data;
@ -119,14 +184,14 @@ gnc_split_register_add_transaction (SplitRegister *reg,
vcell_loc->virt_row++;
}
if (add_blank) {
/* If requested, add an empty split row at the end. */
if (add_empty) {
if (find_trans == trans && find_split == NULL &&
find_class == CURSOR_CLASS_SPLIT) {
*new_split_row = vcell_loc->virt_row;
}
/* Add blank transaction split */
gnc_table_set_vcell(reg->table, split_cursor, xaccSplitGetGUID(NULL),
FALSE, TRUE, *vcell_loc);
vcell_loc->virt_row++;
@ -281,13 +346,16 @@ gnc_split_register_load (SplitRegister *reg, GList * slist,
info->blank_split_guid = *xaccSplitGetGUID (blank_split);
info->blank_split_edited = FALSE;
DEBUG("blank_split=%p", blank_split);
DEBUG("created new blank_split=%p", blank_split);
gnc_resume_gui_refresh ();
}
blank_trans = xaccSplitGetParent (blank_split);
DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p",
blank_split, blank_trans, pending_trans);
info->default_account = *xaccAccountGetGUID (default_account);
table = reg->table;

View File

@ -17,7 +17,7 @@
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
/*
/*
* split-register.c
* author Copyright (c) 1998-2000 Linas Vepstas <linas@linas.org>
* author Copyright (c) 2000-2001 Dave Peticolas <dave@krondo.com>
@ -1433,11 +1433,13 @@ gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
if (trans == blank_trans) {
blank_edited = info->blank_split_edited;
info->last_date_entered = xaccTransGetDate (trans);
/* Q: Why should we nullify the blank split GUID if the blank split
* wasn't edited? We still might not be committing! */
info->blank_split_guid = *guid_null ();
info->blank_split_edited = FALSE;
}
/* We have to clear the pending guid *before* commiting the
/* We have to clear the pending guid *before* committing the
trans, because the event handler will find it otherwise. */
if (trans == pending_trans) {
info->pending_trans_guid = *guid_null ();
@ -1517,9 +1519,20 @@ gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
}
g_assert(xaccTransIsOpen(trans));
/* If we are committing the blank split, add it to the account now */
/* If we are saving a brand new transaction and the blank split hasn't
* been edited, then we need to give it a default account. */
/* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
* even better? What if there were some way that we could be on
* a row other than the transaction row or blank split row, but
* the blank split still hasn't been edited? It seems to be assumed
* that it isn't possible, but... -Charles, Jan 2009 */
if (split == blank_split && !info->blank_split_edited)
{
/* If we've reached this point, it means that the blank split is
* anchoring the transaction - see gnc_split_register_add_transaction()
* for an explanation - and the transaction has been edited (as evidenced
* by the earlier check for a changed cursor.) Since the blank split
* itself has not been edited, we'll have to assign a default account. */
account = gnc_split_register_get_default_account(reg);
if (account)
xaccSplitSetAccount(blank_split, account);
@ -1529,8 +1542,10 @@ gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
if (split == NULL)
{
/* If we were asked to save data for a row for which there is no
* associated split, then assume that this was a row that was
* set aside for adding splits to an existing transaction.
* associated split, then assume that this was an "empty" row - see
* gnc_split_register_add_transaction() for an explanation. This row
* is used to add splits to an existing transaction, or to add the
* 2nd through nth split rows to a brand new transaction.
* xaccSRGetCurrent will handle this case, too. We will create
* a new split, copy the row contents to that split, and append
* the split to the pre-existing transaction. */

View File

@ -1,5 +1,5 @@
/********************************************************************\
* split-register.h -- split register api *
* split-register.h -- split register API *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -20,81 +20,90 @@
* *
\********************************************************************/
/** @addtogroup GUI
@{ */
/** @addtogroup Ledger Checkbook Register
@brief The register is the spreadsheet-like area that looks like a
checkbook register.
@details It displays transactions, and allows the
user to edit transactions in-place. The register does *not*
contain any of the other window decorations that one might want
to have for a free standing window (e.g. menubars, toolbars, etc.)
All user input to the register is handled by the 'cursor', which
is mapped onto one of the displayed rows in the register.
The layout of the register is configurable. There's a broad
variety of cell types to choose from: date cells, which know
how to parse dates; price cells, which know how to parse prices,
etc. These cells can be laid out in any column; even a multi-row
layout is supported. The name 'split-register' is derived from
the fact that this register can display multiple rows of
transaction splits underneath a transaction title/summary row.
@par Design Notes.
@{
Some notes about the "blank split":@n
Q: What is the "blank split"?@n
A: A new, empty split appended to the bottom of the ledger
window. The blank split provides an area where the user
can type in new split/transaction info.
The "blank split" is treated in a special way for a number
of reasons:
- it must always appear as the bottom-most split
in the Ledger window,
- it must be committed if the user edits it, and
a new blank split must be created.
- it must be deleted when the ledger window is closed.
To implement the above, the register "user_data" is used
to store an SRInfo structure containing the blank split.
@}
@par Some notes on Commit/Rollback:
@{
*
* There's an engine component and a gui component to the commit/rollback
* scheme. On the engine side, one must always call BeginEdit()
* before starting to edit a transaction. When you think you're done,
* you can call CommitEdit() to commit the changes, or RollbackEdit() to
* go back to how things were before you started the edit. Think of it as
* a one-shot mega-undo for that transaction.
*
* Note that the query engine uses the original values, not the currently
* edited values, when performing a sort. This allows your to e.g. edit
* the date without having the transaction hop around in the gui while you
* do it.
*
* On the gui side, commits are now performed on a per-transaction basis,
* rather than a per-split (per-journal-entry) basis. This means that
* if you have a transaction with a lot of splits in it, you can edit them
* all you want without having to commit one before moving to the next.
*
* @{
*/
/** @addtogroup Register
* @{
*/
/** @addtogroup SplitRegister Split Register
* @brief GnuCash-specific ledger and journal displays based on
* @ref RegisterCore.
*
* @details The split register is a spreadsheet-like area that looks like
* a checkbook register. It is a GnuCash-specific implementation built
* atop the @ref RegisterCore.
*
* It displays transactions and allows the user to edit them in-place.
* The register does @b not contain any of the other window decorations
* that one might want to have for a free standing window (e.g. menubars,
* toolbars, etc.)
*
* The layout of the register is configurable. There's a broad
* variety of cell types to choose from: date cells, which know
* how to parse dates; price cells, which know how to parse prices,
* etc. These cells can be laid out in any column; even a multi-row
* layout is supported. The name "split register" is derived from
* the fact that this register can display multiple rows of
* transaction splits underneath a transaction title/summary row.
*
* An area for entering new transactions is provided at the bottom of
* the register.
*
* All user input to the register is handled by the 'cursor', which
* is mapped onto one of the displayed rows in the register.
*
* @par Design Notes.
* @{
* Some notes about the "blank split":@n
* Q: What is the "blank split"?@n
* A: A new, empty split appended to the bottom of the ledger
* window. The blank split provides an area where the user
* can type in new split/transaction info.
* The "blank split" is treated in a special way for a number
* of reasons:
* - it must always appear as the bottom-most split
* in the Ledger window,
* - it must be committed if the user edits it, and
* a new blank split must be created.
* - it must be deleted when the ledger window is closed.
*
* To implement the above, the register "user_data" is used
* to store an SRInfo structure containing the blank split.
* @}
*
* @par Some notes on Commit/Rollback:
* @{
* There's an engine component and a gui component to the commit/rollback
* scheme. On the engine side, one must always call BeginEdit()
* before starting to edit a transaction. When you think you're done,
* you can call CommitEdit() to commit the changes, or RollbackEdit() to
* go back to how things were before you started the edit. Think of it as
* a one-shot mega-undo for that transaction.
*
* Note that the query engine uses the original values, not the currently
* edited values, when performing a sort. This allows your to e.g. edit
* the date without having the transaction hop around in the gui while you
* do it.
*
* On the gui side, commits are now performed on a per-transaction basis,
* rather than a per-split (per-journal-entry) basis. This means that
* if you have a transaction with a lot of splits in it, you can edit them
* all you want without having to commit one before moving to the next.
*
* Similarly, the "cancel" button will now undo the changes to all of the
* lines in the transaction display, not just to one line (one split) at a
* time.
*
@}
@par Some notes on Reloads & Redraws:
@{
* @}
*
* @par Some notes on Reloads & Redraws:
* @{
* Reloads and redraws tend to be heavyweight. We try to use change flags
* as much as possible in this code, but imagine the following scenario:
*
* Create two bank accounts. Transfer money from one to the other.
* Open two registers, showing each account. Change the amount in one window.
* Note that the other window also redraws, to show the new correct amount.
*
*
* Since you changed an amount value, potentially *all* displayed
* balances change in *both* register windows (as well as the ledger
* balance in the main window). Three or more windows may be involved
@ -107,27 +116,28 @@ to store an SRInfo structure containing the blank split.
* entry, stating 'this entry has changed since lst time, redraw it'.
* But that still doesn't avoid the overhead of reloading the table
* from the engine.
@}
The Register itself is independent of GnuCash, and is designed
so that it can be used with other applications.
The Ledger is an adaptation of the Register for use by GnuCash.
The Ledger sets up an explicit visual layout, putting certain
types of cells in specific locations (e.g. date on left, summary
in middle, value at right), and hooks up these cells to
the various GnuCash financial objects.
This code is also theoretically independent of the actual GUI
toolkit/widget-set (it once worked with both Motif and Gnome).
The actual GUI-toolkit specific code is supposed to be in a
GUI portability layer. Over the years, some gnome-isms may
have snuck in; these should also be cleaned up.
*/
/** @{
@file split-register.h
@brief API for checkbook register display area
@author Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org>
*/
* @}
*
* The Register itself is independent of GnuCash, and is designed
* so that it can be used with other applications.
* The Ledger is an adaptation of the Register for use by GnuCash.
* The Ledger sets up an explicit visual layout, putting certain
* types of cells in specific locations (e.g. date on left, summary
* in middle, value at right), and hooks up these cells to
* the various GnuCash financial objects.
*
* This code is also theoretically independent of the actual GUI
* toolkit/widget-set (it once worked with both Motif and Gnome).
* The actual GUI-toolkit specific code is supposed to be in a
* GUI portability layer. Over the years, some gnome-isms may
* have snuck in; these should also be cleaned up.
*
* @{
*/
/** @file split-register.h
* @brief API for checkbook register display area
* @author Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org>
*/
/** @{ */
#ifndef SPLIT_REGISTER_H
@ -251,7 +261,7 @@ struct split_register
SplitRegisterType type;
SplitRegisterStyle style;
gboolean use_double_line; /**< whether to use two lines per tranasaction */
gboolean use_double_line; /**< whether to use two lines per transaction */
gboolean is_template;
gboolean do_auto_complete; /**< whether to use auto-competion */
@ -357,7 +367,7 @@ CursorClass gnc_split_register_get_cursor_class
/** Gets the transaction at the current cursor location, which may be on
* the transaction itself or on any of its splits.
*
*
* @param reg a ::SplitRegister
*
* @return the ::Transaction at the cursor location, or @c NULL
@ -366,7 +376,7 @@ Transaction * gnc_split_register_get_current_trans (SplitRegister *reg);
/** Gets the anchoring split of the transaction at the current cursor location,
* which may be on the transaction itself or on any of its splits.
*
*
* @param reg a ::SplitRegister
*
* @param vcell_loc a pointer to be filled with the location of the
@ -379,7 +389,7 @@ gnc_split_register_get_current_trans_split (SplitRegister *reg,
VirtualCellLocation *vcell_loc);
/** Returns the split at which the cursor is currently located.
*
*
* @param reg a ::SplitRegister
*
* @return the ::Split at the cursor location, or the anchoring split
@ -388,7 +398,7 @@ gnc_split_register_get_current_trans_split (SplitRegister *reg,
Split * gnc_split_register_get_current_split (SplitRegister *reg);
/** Gets the blank split for a register.
*
*
* @param reg a ::SplitRegister
*
* @return the ::Split used as the blank split, or @c NULL if
@ -483,10 +493,11 @@ void gnc_split_register_cancel_cursor_trans_changes (SplitRegister *reg);
/** Populates the rows of a register.
*
* The rows are filled, based on the register style, with data associated
* with the given list of splits, @a slist. In addition, a new, blank split
* is appended to the tail end of the register. This "blank split" is
* the place where the user can create new transactions.
* The account @a default_account, if provided, is used to determine default
* with the given list of splits @a slist. In addition, an area for the
* user to begin entering new transactions is placed at the tail end of the
* register. This area is anchored by the "blank split".
*
* The account @a default_account, if provided, is used to determine
* various default values for the blank split (such as currency, last check
* number, and transfer account) for the blank split.
*
@ -552,6 +563,7 @@ gnc_split_register_begin_edit_or_warn(SRInfo *info, Transaction *trans);
/** @} */
/** @} */
/** @} */
/** @} */
/* -------------------------------------------------------------- */
/** Private function -- outsiders must not use this */

View File

@ -20,6 +20,39 @@
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
/** @addtogroup GUI
* @{
*/
/** @addtogroup Register Registers, Ledgers and Journals
* @{
*/
/** @addtogroup RegisterCore Register Core
* @brief An infrastructure for building a modular matrix of cells like a
* spreadsheet or checkbook register.
*
* @details Each cell may be specialized to perform a particular function,
* e.g. to read dates, numerical amounts, or text. The register core 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
* spreadsheets.
*
* The register core is built from several types of components: Cells,
* Cellblocks, Cursors, and the Table.
*
* The register core should not have any 'knowledge' of the accounting model
* of GnuCash or of the workings of the main application. It should not be
* specific to a particular GUI (such as Gnome/GTK). It should be possible
* to use the register core in a stand-alone fashion.
*
* For information on the GnuCash-specific register implementation that has
* been built atop this core, see @ref SplitRegister.
*
* @{
*/
/** @file register-common.h
* @brief Common declarations for the register core
* @author Copyright (c) 2000 Dave Peticolas
*/
#ifndef REGISTER_COMMON_H
#define REGISTER_COMMON_H
@ -82,3 +115,6 @@ struct _VirtualLocation {
gboolean virt_loc_equal (VirtualLocation vl1, VirtualLocation vl2);
#endif
/** @} */
/** @} */
/** @} */