Last bigpatch.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2024 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas 2000-02-27 22:14:58 +00:00
parent bd1d5e2c62
commit 11529e91c1
54 changed files with 4665 additions and 874 deletions

View File

@ -33,6 +33,7 @@
#include "Transaction.h"
#include "util.h"
/** GLOBALS *********************************************************/
/* These are globals because they describe the state of the entire session.
* The is, there must be only one instance of these per GUI session.
@ -209,7 +210,7 @@ xaccLedgerDisplaySimple (Account *acc)
xaccLedgerDisplay *
xaccLedgerDisplayAccGroup (Account *acc)
{
{
xaccLedgerDisplay *retval;
Account **list;
int ledger_type;
@ -271,7 +272,7 @@ xaccLedgerDisplayAccGroup (Account *acc)
if (list) _free (list);
return retval;
}
}
static gncUIWidget
xaccLedgerDisplayParent(void *user_data)
@ -287,6 +288,20 @@ xaccLedgerDisplayParent(void *user_data)
return (regData->get_parent)(regData);
}
static void
xaccLedgerDisplaySetHelp(void *user_data, const char *help_str)
{
xaccLedgerDisplay *regData = user_data;
if (regData == NULL)
return;
if (regData->set_help == NULL)
return;
(regData->set_help)(regData, help_str);
}
/********************************************************************\
* xaccLedgerDisplayLedger *
* opens up a ledger window for a list of accounts *
@ -300,8 +315,8 @@ xaccLedgerDisplayParent(void *user_data)
xaccLedgerDisplay *
xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
{
xaccLedgerDisplay *regData = NULL;
{
xaccLedgerDisplay *regData = NULL;
/******************************************************************\
\******************************************************************/
@ -340,6 +355,7 @@ xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
regData->redraw = NULL;
regData->destroy = NULL;
regData->get_parent = NULL;
regData->set_help = NULL;
regData->gui_hook = NULL;
regData->dirty = 0;
regData->balance = 0.0;
@ -373,7 +389,9 @@ xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
* but will not do the gui init */
regData->ledger = xaccMallocSplitRegister (ledger_type);
xaccSRSetData(regData->ledger, regData, xaccLedgerDisplayParent);
xaccSRSetData(regData->ledger, regData,
xaccLedgerDisplayParent,
xaccLedgerDisplaySetHelp);
regData->dirty = 1;
xaccLedgerDisplayRefresh (regData);

View File

@ -32,6 +32,7 @@
#include "SplitLedger.h"
#include "Transaction.h"
/* the MAX_QUERY_SPLITS define determines how many transactions should be shown
* in the register. Its set to a default of 30. But this should be converted
* into a user-configurable value. So hack-alert on the configuration aspect.
@ -72,6 +73,7 @@ struct _xaccLedgerDisplay {
void (*redraw) (xaccLedgerDisplay *); /* redraw callback */
void (*destroy) (xaccLedgerDisplay *); /* destroy callback */
gncUIWidget (*get_parent) (xaccLedgerDisplay *); /* get parent widget */
void (*set_help) (xaccLedgerDisplay *, const char *); /* help string */
};

View File

@ -126,6 +126,9 @@ gnc_transaction_ui_refresh(Transaction *trans)
Split *split;
int i, num_splits;
if (trans == NULL)
return;
xaccTransDisplayRefresh(trans);
num_splits = xaccTransCountSplits(trans);

View File

@ -127,7 +127,10 @@ struct _SRInfo
void *user_data;
/* hook to get parent widget */
gncUIWidget (*get_parent) (void * user_data);
SRGetParentCallback get_parent;
/* hook to set help string */
SRSetHelpCallback set_help;
};
@ -156,6 +159,8 @@ static int force_double_entry_awareness = 0;
/* This static indicates the debugging module that this .o belongs to. */
static short module = MOD_LEDGER;
/* The character used to separate accounts. */
static char account_separator = ':';
/* static prototypes */
static Transaction * xaccSRGetTrans (SplitRegister *reg,
@ -220,7 +225,8 @@ xaccSRGetParent(SplitRegister *reg)
void
xaccSRSetData(SplitRegister *reg, void *user_data,
SRGetParentCallback get_parent)
SRGetParentCallback get_parent,
SRSetHelpCallback set_help)
{
SRInfo *info = xaccSRGetInfo(reg);
@ -228,6 +234,13 @@ xaccSRSetData(SplitRegister *reg, void *user_data,
info->user_data = user_data;
info->get_parent = get_parent;
info->set_help = set_help;
}
void
xaccSRSetAccountSeparator(char separator)
{
account_separator = separator;
}
/* ======================================================== */
@ -387,6 +400,20 @@ LedgerTraverse (Table *table,
/* ======================================================== */
static void
LedgerSetHelp (Table *table, const char *help_str, void *client_data)
{
SplitRegister *reg = client_data;
SRInfo *info = xaccSRGetInfo(reg);
if (info->set_help == NULL)
return;
info->set_help(info->user_data, help_str);
}
/* ======================================================== */
static void
LedgerDestroy (SplitRegister *reg)
{
@ -484,10 +511,8 @@ xaccSRGetCurrentTrans (SplitRegister *reg)
}
split = (Split *) reg->table->user_data[vr][vc];
if (split == NULL) {
PERR ("Internal Error: xaccSRGetCurrentTrans(): no parent \n");
if (split == NULL)
return NULL;
}
return xaccSplitGetParent(split);
}
@ -961,8 +986,8 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
}
if (MOD_MEMO & changed) {
DEBUG ("xaccSRSaveRegEntry(): MOD_MEMO: %s\n", reg->memoCell->value);
xaccSplitSetMemo (split, reg->memoCell->value);
DEBUG ("xaccSRSaveRegEntry(): MOD_MEMO: %s\n", reg->memoCell->cell.value);
xaccSplitSetMemo (split, reg->memoCell->cell.value);
}
/* -------------------------------------------------------------- */
@ -980,12 +1005,17 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
/* do some reparenting. Insertion into new account will automatically
* delete this split from the old account */
old_acc = xaccSplitGetAccount (split);
new_acc = xaccGetAccountByName (trans, reg->xfrmCell->cell.value);
xaccAccountInsertSplit (new_acc, split);
/* make sure any open windows of the old account get redrawn */
gnc_account_ui_refresh(old_acc);
gnc_refresh_main_window();
new_acc = xaccGetAccountByFullName (trans, reg->xfrmCell->cell.value,
account_separator);
if (old_acc != new_acc)
{
xaccAccountInsertSplit (new_acc, split);
/* make sure any open windows of the old account get redrawn */
gnc_account_ui_refresh(old_acc);
gnc_refresh_main_window();
}
}
if (MOD_MXFRM & changed) {
@ -1023,12 +1053,17 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
/* do some reparenting. Insertion into new account will automatically
* delete from the old account */
old_acc = xaccSplitGetAccount (other_split);
new_acc = xaccGetAccountByName (trans, reg->mxfrmCell->cell.value);
xaccAccountInsertSplit (new_acc, other_split);
/* make sure any open windows of the old account get redrawn */
gnc_account_ui_refresh(old_acc);
gnc_refresh_main_window();
new_acc = xaccGetAccountByFullName (trans, reg->mxfrmCell->cell.value,
account_separator);
if (old_acc != new_acc)
{
xaccAccountInsertSplit (new_acc, other_split);
/* make sure any open windows of the old account get redrawn */
gnc_account_ui_refresh(old_acc);
gnc_refresh_main_window();
}
}
}
@ -1043,10 +1078,17 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
*/
if ((MOD_AMNT | MOD_NAMNT) & changed) {
double new_amount;
double credit;
double debit;
if (MOD_AMNT & changed) {
new_amount = (reg->creditCell->amount) - (reg->debitCell->amount);
credit = xaccGetPriceCellValue(reg->creditCell);
debit = xaccGetPriceCellValue(reg->debitCell);
new_amount = credit - debit;
} else {
new_amount = (reg->ndebitCell->amount) - (reg->ncreditCell->amount);
credit = xaccGetPriceCellValue(reg->ncreditCell);
debit = xaccGetPriceCellValue(reg->ndebitCell);
new_amount = debit - credit;
}
DEBUG ("xaccSRSaveRegEntry(): MOD_AMNT: %f\n", new_amount);
if ((EQUITY_REGISTER == (reg->type & REG_TYPE_MASK)) ||
@ -1062,9 +1104,13 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
if (MOD_PRIC & changed) {
Account *acc;
double price;
int n;
DEBUG ("xaccSRSaveRegEntry(): MOD_PRIC: %f\n", reg->priceCell->amount);
xaccSplitSetSharePrice (split, reg->priceCell->amount);
price = xaccGetPriceCellValue(reg->priceCell);
DEBUG ("xaccSRSaveRegEntry(): MOD_PRIC: %f\n", price);
xaccSplitSetSharePrice (split, price);
/* Here we handle a very special case: the user just created
* an account, which now has two splits in it, and the user
@ -1089,7 +1135,7 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
if (DEQ (currprice, 1.0)) {
t = xaccSplitGetParent (s);
xaccTransBeginEdit (t, 0);
xaccSplitSetSharePrice (s, reg->priceCell->amount);
xaccSplitSetSharePrice (s, price);
xaccTransCommitEdit (t);
}
}
@ -1097,8 +1143,10 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
}
if (MOD_VALU & changed) {
DEBUG ("xaccSRSaveRegEntry(): MOD_VALU: %f\n", reg->valueCell->amount);
xaccSplitSetValue (split, (reg->valueCell->amount));
double value = xaccGetPriceCellValue(reg->valueCell);
DEBUG ("xaccSRSaveRegEntry(): MOD_VALU: %f\n", value);
xaccSplitSetValue (split, value);
}
PINFO ("xaccSRSaveRegEntry(): finished saving split %s of trans %s \n",
@ -1133,12 +1181,12 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
char buff[2];
double baln;
int typo = reg->type & REG_TYPE_MASK;
/* int style = reg->type & REG_STYLE_MASK; */
/* don't even bother doing a load if there is no current cursor */
if (!(reg->table->current_cursor)) return;
ENTER ("SRLoadTransEntry(): s=%p commit=%d\n", split, do_commit);
if (!split) {
/* we interpret a NULL split as a blank split */
xaccSetDateCellValueSecs (reg->dateCell, 0);
@ -1149,7 +1197,7 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
xaccSetPriceCellValue (reg->balanceCell, 0.0);
xaccSetComboCellValue (reg->actionCell, "");
xaccSetBasicCellValue (reg->memoCell, "");
xaccSetQuickFillCellValue (reg->memoCell, "");
xaccSetComboCellValue (reg->xfrmCell, "");
xaccSetComboCellValue (reg->mxfrmCell, "");
xaccSetDebCredCellValue (reg->debitCell,
@ -1198,12 +1246,19 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
* if there are exactly two splits.
* xfrm is the "straight" display, "mxfrm" is the "mirrored" display.
*/
accname = xaccAccountGetName (xaccSplitGetAccount (split));
accname = xaccAccountGetFullName (xaccSplitGetAccount (split),
account_separator);
xaccSetComboCellValue (reg->xfrmCell, accname);
free(accname);
{
Split *s = xaccGetOtherSplit (split);
gncBoolean need_to_free = GNC_F;
if (s) {
accname = xaccAccountGetName (xaccSplitGetAccount (s));
accname = xaccAccountGetFullName (xaccSplitGetAccount (s),
account_separator);
need_to_free = GNC_T;
} else {
/* determine whether s is null because threre are three
* or more splits, or whether there is only one ... */
@ -1215,9 +1270,11 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
}
}
xaccSetComboCellValue (reg->mxfrmCell, accname);
if (need_to_free)
free(accname);
}
xaccSetBasicCellValue (reg->memoCell, xaccSplitGetMemo (split));
xaccSetQuickFillCellValue (reg->memoCell, xaccSplitGetMemo (split));
buff[0] = xaccSplitGetReconcile (split);
buff[1] = 0x0;
@ -1459,6 +1516,8 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
CellBlock *lead_cursor;
gncBoolean found_pending = GNC_F;
xaccSplitRegisterConfigColors (reg);
info->default_source_account = default_source_acc;
table = reg->table;
@ -1546,8 +1605,9 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
vrow ++;
phys_row += reg->trans_cursor->numRows;
/* loop over all of the splits in the transaction */
/* the do..while will automaticaly put a blank (null) split at the end */
/* loop over all of the splits in the transaction. The
* do..while will automaticaly put a blank (null) split
* at the end. */
trans = xaccSplitGetParent (split);
j = 0;
do {
@ -1662,9 +1722,14 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
xaccRefreshTableGUI (table);
/* set the completion character for the xfer cells */
xaccComboCellSetCompleteChar (reg->mxfrmCell, account_separator);
xaccComboCellSetCompleteChar (reg->xfrmCell, account_separator);
/* enable callback for cursor user-driven moves */
table->move_cursor = LedgerMoveCursor;
table->traverse = LedgerTraverse;
table->set_help = LedgerSetHelp;
table->client_data = (void *) reg;
}
@ -1677,6 +1742,7 @@ LoadXferCell (ComboCell *cell,
char *base_currency, char *base_security)
{
Account * acc;
char *name;
int n;
ENTER ("LoadXferCell(): curr=%s secu=%s\n", base_currency, base_security);
@ -1698,19 +1764,26 @@ LoadXferCell (ComboCell *cell,
if (secu && (0x0 == secu[0])) secu = 0x0;
DEBUG ("LoadXferCell(): curr=%s secu=%s acct=%s\n",
curr, secu, xaccAccountGetName (acc));
curr, secu, xaccAccountGetName (acc));
if ( (!safe_strcmp(curr,base_currency)) ||
(!safe_strcmp(curr,base_security)) ||
(secu && (!safe_strcmp(secu,base_currency))) ||
(secu && (!safe_strcmp(secu,base_security))) )
{
xaccAddComboCellMenuItem (cell, xaccAccountGetName (acc));
name = xaccAccountGetFullName (acc, account_separator);
if (name != NULL)
{
xaccAddComboCellMenuItem (cell, name);
free(name);
}
}
LoadXferCell (cell, xaccAccountGetChildren (acc),
base_currency, base_security);
n++;
acc = xaccGroupGetAccount (grp, n);
}
LEAVE ("LoadXferCell()\n");
}

View File

@ -42,7 +42,7 @@ COMMON_SRCS := basiccell.c cellblock.c \
datecell.c pricecell.c QuickFill.c quickfillcell.c \
recncell.c splitreg.c \
table-allgui.c table-html.c textcell.c
MOTIF_SRCS := table-motif.c combocell-motif.c
MOTIF_SRCS := table-motif.c combocell-motif.c quickfillcell-motif.c
GNOME_SRCS := table-gnome.c
QT_SRCS := table-qt.cpp combocell-qt.cpp
CLEAN_SUBDIRS := gnome

View File

@ -110,23 +110,72 @@ xaccGetQuickFill( QuickFill *qf, char c )
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillStr( QuickFill *qf, const char *str )
xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len )
{
if (str == NULL)
return NULL;
while (*str != '\0')
while ((*str != '\0') && (len > 0))
{
if (qf == NULL)
return NULL;
qf = qf->qf[CHAR_TO_INDEX(*str)];
str++;
len--;
}
return qf;
}
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillStr( QuickFill *qf, const char *str )
{
if (str == NULL)
return NULL;
return xaccGetQuickFillStrLen(qf, str, strlen(str));
}
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillUniqueLen( QuickFill *qf, int * length )
{
int last = 0;
int count;
int i;
*length = 0;
if (qf == NULL)
return NULL;
while (1)
{
count = 0;
for( i=0; i<QFNUM; i++ )
{
if (qf->qf[i] != NULL)
{
count++;
if (count > 1)
return qf;
last = i;
}
}
if (count == 0)
return qf;
qf = qf->qf[last];
(*length)++;
}
}
/********************************************************************\
\********************************************************************/
void

View File

@ -66,6 +66,8 @@ QuickFill *xaccMallocQuickFill( void );
void xaccFreeQuickFill( QuickFill *qf );
QuickFill *xaccGetQuickFill( QuickFill *qf, char c );
QuickFill *xaccGetQuickFillStr( QuickFill *qf, const char *str );
QuickFill *xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len );
QuickFill *xaccGetQuickFillUniqueLen( QuickFill *qf, int *len );
void xaccQFInsertText( QuickFill *qf, const char *text, QuickFillSort );
/** GLOBALS *********************************************************/

View File

@ -43,6 +43,20 @@ BasicCell * xaccMallocBasicCell (void)
/* ===================================================== */
static char *
BasicCellHelpValue(BasicCell *cell)
{
if ((cell->value != NULL) && (cell->value[0] != 0))
return strdup(cell->value);
if (cell->blank_help != NULL)
return strdup(cell->blank_help);
return NULL;
}
/* ===================================================== */
void xaccInitBasicCell (BasicCell *cell)
{
cell->input_output = XACC_CELL_ALLOW_ALL;
@ -50,15 +64,18 @@ void xaccInitBasicCell (BasicCell *cell)
cell->fg_color = 0x0; /* black */
cell->use_bg_color = 0; /* ignore the color */
cell->use_fg_color = 0; /* ignore the color */
cell->value = 0x0;
cell->value = NULL;
cell->blank_help = NULL;
cell->changed = 0;
cell->set_value = NULL;
cell->enter_cell = NULL;
cell->modify_verify = NULL;
cell->direct_update = NULL;
cell->leave_cell = NULL;
cell->realize = NULL;
cell->move = NULL;
cell->destroy = NULL;
cell->get_help_value = BasicCellHelpValue;
cell->gui_private = NULL;
}
@ -76,6 +93,10 @@ void xaccDestroyBasicCell (BasicCell *cell)
free (cell->value);
}
if (cell->blank_help) {
free (cell->blank_help);
}
/* help prevent access to freed memory */
xaccInitBasicCell (cell);
@ -106,4 +127,35 @@ void xaccSetBasicCellValue (BasicCell *cell, const char *val)
}
}
/* ===================================================== */
void
xaccSetBasicCellBlankHelp (BasicCell *cell, const char *blank_help)
{
if (cell == NULL)
return;
if (cell->blank_help != NULL)
free(cell->blank_help);
if (blank_help == NULL)
cell->blank_help = NULL;
else
cell->blank_help = strdup(blank_help);
}
/* ===================================================== */
char *
xaccBasicCellGetHelp (BasicCell *cell)
{
if (cell == NULL)
return NULL;
if (cell->get_help_value == NULL)
return NULL;
return cell->get_help_value(cell);
}
/* ================== end of file ====================== */

View File

@ -114,6 +114,14 @@
* It must return a string, or void if it rejects the change.
* The returned string will be used to update the cell value.
*
* The direct_update() callback is called to pass raw gui data
* to the cell. The exact format of the data is determined
* by the gui. The callback should return TRUE if the event
* was handled, i.e., there is no need to call the modify
* update. If the value needs to be changed, the newval_ptr
* should be set to a malloc'd new value. The other arguments
* work as above.
*
* Some memory management rules:
* (1) the callback must not modify the values of old, change, new
* (2) if the callback likes the new string, it may return the
@ -177,6 +185,8 @@
#ifndef __XACC_BASIC_CELL_H__
#define __XACC_BASIC_CELL_H__
#include "gnc-common.h"
/* define a bitmask */
#define XACC_CELL_ALLOW_NONE 0x0
#define XACC_CELL_ALLOW_SHADOW 0x1
@ -185,7 +195,6 @@
#define XACC_CELL_ALLOW_EXACT_ONLY 0x4
typedef struct _BasicCell BasicCell;
typedef unsigned int uint32;
struct _BasicCell {
@ -200,6 +209,7 @@ struct _BasicCell {
/* ==================================================== */
char * value; /* current value */
char *blank_help; /* help when value is blank */
unsigned int changed; /* 2^32-1 if value modified */
char input_output; /* zero if output-only */
@ -221,6 +231,13 @@ struct _BasicCell {
int *cursor_position,
int *start_selection,
int *end_selection);
gncBoolean (*direct_update) (BasicCell *,
const char *oldval,
char **newval_ptr,
int *cursor_position,
int *start_selection,
int *end_selection,
void *gui_data);
const char * (*leave_cell) (BasicCell *,
const char * current);
@ -232,16 +249,20 @@ struct _BasicCell {
int phys_row, int phys_col);
void (* destroy) (BasicCell *);
char * (*get_help_value) (BasicCell *);
/* general hook for gui-private data */
void * gui_private;
};
BasicCell * xaccMallocBasicCell (void);
BasicCell * xaccMallocBasicCell (void);
void xaccInitBasicCell (BasicCell *);
void xaccDestroyBasicCell (BasicCell *);
void xaccSetBasicCellValue (BasicCell *, const char *);
void xaccSetBasicCellBlankHelp (BasicCell *, const char *);
char * xaccBasicCellGetHelp (BasicCell *);
#endif /* __XACC_BASIC_CELL_H__ */
/* ------------------ end of file ---------------------- */

View File

@ -39,8 +39,9 @@ CellBlock * xaccMallocCellBlock (int numrows, int numcols)
arr->numRows = 0;
arr->numCols = 0;
arr->active_bg_color = 0xffffff; /* white */
arr->passive_bg_color = 0xffffff; /* white */
arr->active_bg_color = 0xffffff; /* white */
arr->passive_bg_color = 0xffffff; /* white */
arr->passive_bg_color2 = 0xffffff; /* white */
arr->user_data = NULL;
arr->cells = NULL;

View File

@ -88,10 +88,14 @@ struct _CellBlock {
* the currently active cursor).
*
* The passive_bg_color is the default color for the cell background
* (in argb format) when the cell block is not highlighted.
* (in argb format) of the first row when the cell block is not highlighted.
*
* The passive_bg_color2 is the default color for cell backgrounds
* in other rows of the cellblock when it is not highlighted.
*/
uint32 active_bg_color;
uint32 passive_bg_color;
uint32 passive_bg_color2;
/* other attributes */
short *widths; /* column widths */

View File

@ -583,4 +583,25 @@ void xaccComboCellSetStrict (ComboCell *cell, gncBoolean strict)
{
}
/* =============================================== */
void
xaccComboCellSetCompleteChar (ComboCell *cell, char complete_char)
{
}
/* =============================================== */
void
xaccComboCellSetIgnoreString (ComboCell *cell, const char *ignore_string)
{
}
/* =============================================== */
void
xaccComboCellSetIgnoreHelp (ComboCell *cell, const char *ignore_help)
{
}
/* =============== end of file =================== */

View File

@ -44,7 +44,7 @@
typedef struct _ComboCell {
BasicCell cell;
char ** menuitems; /* not used in the gnome version */
char ** menuitems; /* not used in the gnome version */
} ComboCell;
ComboCell * xaccMallocComboCell (void);
@ -61,6 +61,21 @@ void xaccAddComboCellMenuItem (ComboCell *, char * menustr);
* to strict, i.e., only menu items are accepted. */
void xaccComboCellSetStrict (ComboCell *, gncBoolean);
/* Only functional in Gnome, right now. Sets a character used
* for special completion processing. */
void xaccComboCellSetCompleteChar (ComboCell *, char);
/* Only functional in Gnome, right now. Sets a string which,
* if the cell has that value, will be returned on an enter,
* thus preventing the cell from being edited. This is used
* for transactions with multiple splits. */
void xaccComboCellSetIgnoreString (ComboCell *, const char *);
/* Only functional in Gnome, right now. Sets a string which,
* if the cell has the ignore value, will be returned as the
* help string. */
void xaccComboCellSetIgnoreHelp (ComboCell *, const char *);
#endif /* __XACC_COMBO_CELL_H__ */
/* --------------- end of file ---------------------- */

View File

@ -54,8 +54,8 @@ static short module = MOD_REGISTER;
/* ================================================ */
static
void xaccParseDate (struct tm *parsed, const char * datestr)
static void
xaccParseDate (struct tm *parsed, const char * datestr)
{
int iday, imonth, iyear;
if (!parsed) return;
@ -121,6 +121,43 @@ xaccValidateDate (struct tm *date, int recur)
}
/* ================================================ */
static char *
DateCellHelpValue(BasicCell *bcell)
{
DateCell *cell = (DateCell *) bcell;
if ((bcell->value != NULL) && (bcell->value[0] != 0))
{
char string[1024];
struct tm time;
memset(&time, 0, sizeof(time));
if (bcell->value != NULL)
xaccParseDate (&time, bcell->value);
else
{
time.tm_mday = cell->date.tm_mday;
time.tm_mon = cell->date.tm_mon;
time.tm_year = cell->date.tm_year;
}
xaccValidateDate(&time, GNC_F);
mktime(&time);
strftime(string, sizeof(string), "%A %d %B %Y", &time);
return strdup(string);
}
if (bcell->blank_help != NULL)
return strdup(bcell->blank_help);
return NULL;
}
/* ================================================ */
static const char *
@ -150,32 +187,56 @@ DateMV (BasicCell *_cell,
int *end_selection)
{
DateCell *cell = (DateCell *) _cell;
gncBoolean accept = GNC_F;
gncBoolean accel = GNC_F;
struct tm *date;
char buff[30];
char *datestr;
int accel=0;
short accept=0;
/* if user hit backspace, accept the change */
if (!change) accept=1;
else if (0x0 == change[0]) accept=1;
if (change == NULL) accept = GNC_T;
else if (0x0 == change[0]) accept = GNC_T;
else
{
int i, count = 0;
char separator = dateSeparator();
gncBoolean ok = GNC_T;
/* accept any numeric input */
else if (isdigit (change[0])) accept=1;
for (i=0; 0 != change[i]; i++)
{
/* accept only numbers or a date separator. Note that the
* separator of '-' (for DATE_FORMAT_ISO) takes precedence
* over the accelerator below! */
if (!isdigit(change[i]) && (separator != change[i]))
ok = GNC_F;
/* accept the separator character */
/* Note that the separator of '-' (for DATE_FORMAT_ISO) takes precedence
over the accelerator below! */
else if (dateSeparator() == change[0]) accept=1;
if (separator == change[i])
count++;
}
for (i=0; 0 != oldval[i]; i++)
if (separator == oldval[i])
count++;
if (2 < count)
ok = GNC_F;
if (ok)
accept = GNC_T;
}
/* keep a copy of the new value */
if (accept) {
if (cell->cell.value) free (cell->cell.value);
cell->cell.value = strdup (newval);
xaccParseDate (&(cell->date), newval);
return newval;
}
/* otherwise, maybe its an accelerator key. */
if (strlen(change) != 1)
return NULL;
date = &(cell->date);
/* handle accelerator keys */
@ -184,28 +245,28 @@ DateMV (BasicCell *_cell,
case '=':
/* increment day */
date->tm_mday ++;
accel = 1;
accel = GNC_T;
break;
case '_':
case '-':
/* decrement day */
date->tm_mday --;
accel = 1;
accel = GNC_T;
break;
case '}':
case ']':
/* increment month */
date->tm_mon ++;
accel = 1;
accel = GNC_T;
break;
case '{':
case '[':
/* decrment month */
date->tm_mon --;
accel = 1;
accel = GNC_T;
break;
case 'M':
@ -261,7 +322,7 @@ DateMV (BasicCell *_cell,
cell->cell.value = strdup (buff);
datestr = strdup (buff);
return datestr;
}
@ -279,8 +340,8 @@ DateLeave (BasicCell *_cell, const char * curr)
xaccParseDate (&(cell->date), curr);
printDate (buff, cell->date.tm_mday,
cell->date.tm_mon+1,
cell->date.tm_year+1900);
cell->date.tm_mon+1,
cell->date.tm_year+1900);
if (cell->cell.value) free (cell->cell.value);
cell->cell.value = strdup (buff);
@ -346,6 +407,7 @@ xaccInitDateCell (DateCell *cell)
cell->cell.modify_verify = DateMV;
cell->cell.leave_cell = DateLeave;
cell->cell.set_value = setDateCellValue;
cell->cell.get_help_value = DateCellHelpValue;
}
/* ================================================ */
@ -456,8 +518,8 @@ setDateCellValue (BasicCell *_cell, const char *str)
xaccParseDate (&(cell->date), str);
printDate (buff, cell->date.tm_mday,
cell->date.tm_mon+1,
cell->date.tm_year+1900);
cell->date.tm_mon+1,
cell->date.tm_year+1900);
if (cell->cell.value) free (cell->cell.value);
cell->cell.value = strdup (buff);

View File

@ -42,7 +42,7 @@ LIBS = -L$(prefix)/lib @LIBS@ \
# See Makefile.common for information about these variables.
GNOME_SRCS := gnucash-sheet.c gnucash-grid.c gnucash-color.c gnucash-cursor.c \
gnucash-item-edit.c gnucash-style.c combocell-gnome.c \
gnucash-header.c gnucash-item-list.c
gnucash-header.c gnucash-item-list.c quickfillcell-gnome.c
######################################################################
default: gnome

View File

@ -31,6 +31,8 @@
own strings.
*/
#include "config.h"
#include <gnome.h>
#include "splitreg.h"
@ -41,6 +43,7 @@
#include "gnucash-item-edit.h"
#include "gnucash-item-list.h"
#include "global-options.h"
#include "messages.h"
#include "util.h"
@ -53,8 +56,10 @@ typedef struct _PopBox
GNCItemList *item_list;
gint select_item_signal;
gint change_item_signal;
gint key_press_signal;
gboolean list_signals_connected;
gboolean signals_connected; /* list signals connected? */
gboolean list_in_sync; /* list in sync with menustrings? */
gboolean list_sorted; /* list has been sorted? */
@ -64,13 +69,21 @@ typedef struct _PopBox
gboolean in_list_select;
gncBoolean strict;
char complete_char; /* char to be used for auto-completion */
gchar *ignore_string;
gchar *ignore_help;
} PopBox;
static void block_list_signals (ComboCell *cell);
static void unblock_list_signals (ComboCell *cell);
static void realizeCombo (BasicCell *bcell, void *w, int width);
static void moveCombo (BasicCell *bcell, int phys_row, int phys_col);
static void destroyCombo (BasicCell *bcell);
static const char * enterCombo (BasicCell *bcell, const char *value,
static const char * enterCombo (BasicCell *bcell,
const char *value,
int *cursor_position,
int *start_selection,
int *end_selection);
@ -101,13 +114,13 @@ void xaccInitComboCell (ComboCell *cell)
cell->cell.realize = realizeCombo;
cell->cell.destroy = destroyCombo;
box = g_new(PopBox, 1);
box = g_new0(PopBox, 1);
box->sheet = NULL;
box->item_edit = NULL;
box->item_list = NULL;
box->menustrings = NULL;
box->list_signals_connected = FALSE;
box->signals_connected = FALSE;
box->list_in_sync = TRUE;
box->list_sorted = TRUE;
box->list_popped = FALSE;
@ -118,6 +131,11 @@ void xaccInitComboCell (ComboCell *cell)
box->in_list_select = FALSE;
box->strict = TRUE;
box->complete_char = 0;
box->ignore_string = NULL;
box->ignore_help = NULL;
}
/* =============================================== */
@ -136,6 +154,17 @@ select_item_cb (GNCItemList *item_list, char *item_string, gpointer data)
box->list_popped = FALSE;
}
static void
change_item_cb (GNCItemList *item_list, char *item_string, gpointer data)
{
ComboCell *cell = (ComboCell *) data;
PopBox *box = (PopBox *) cell->cell.gui_private;
box->in_list_select = TRUE;
gnucash_sheet_modify_current_cell(box->sheet, item_string);
box->in_list_select = FALSE;
}
static void
key_press_item_cb (GNCItemList *item_list, GdkEventKey *event, gpointer data)
{
@ -155,11 +184,11 @@ key_press_item_cb (GNCItemList *item_list, GdkEventKey *event, gpointer data)
}
static void
disconnect_list_signals (ComboCell *cell)
combo_disconnect_signals (ComboCell *cell)
{
PopBox *box = (PopBox *) cell->cell.gui_private;
if (!box->list_signals_connected)
if (!box->signals_connected)
return;
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list)))
@ -168,18 +197,21 @@ disconnect_list_signals (ComboCell *cell)
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->select_item_signal);
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->change_item_signal);
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->key_press_signal);
box->list_signals_connected = FALSE;
box->signals_connected = FALSE;
}
static void
connect_list_signals (ComboCell *cell)
combo_connect_signals (ComboCell *cell)
{
PopBox *box = (PopBox *) cell->cell.gui_private;
if (box->list_signals_connected)
if (box->signals_connected)
return;
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list)))
@ -190,13 +222,54 @@ connect_list_signals (ComboCell *cell)
GTK_SIGNAL_FUNC(select_item_cb),
(gpointer) cell);
box->change_item_signal =
gtk_signal_connect(GTK_OBJECT(box->item_list), "change_item",
GTK_SIGNAL_FUNC(change_item_cb),
(gpointer) cell);
box->key_press_signal =
gtk_signal_connect(GTK_OBJECT(box->item_list),
"key_press_event",
GTK_SIGNAL_FUNC(key_press_item_cb),
(gpointer) cell);
box->list_signals_connected = TRUE;
box->signals_connected = TRUE;
}
static void
block_list_signals (ComboCell *cell)
{
PopBox *box = (PopBox *) cell->cell.gui_private;
if (!box->signals_connected)
return;
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
box->select_item_signal);
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
box->change_item_signal);
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
box->key_press_signal);
}
static void
unblock_list_signals (ComboCell *cell)
{
PopBox *box = (PopBox *) cell->cell.gui_private;
if (!box->signals_connected)
return;
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
box->select_item_signal);
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
box->change_item_signal);
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
box->key_press_signal);
}
/* =============================================== */
@ -210,7 +283,7 @@ destroyCombo (BasicCell *bcell)
if (cell->cell.realize == NULL)
{
if (box != NULL && box->item_list != NULL) {
disconnect_list_signals(cell);
combo_disconnect_signals(cell);
gtk_object_unref(GTK_OBJECT(box->item_list));
box->item_list = NULL;
}
@ -241,6 +314,9 @@ void xaccDestroyComboCell (ComboCell *cell)
xaccFreeQuickFill(box->qf);
box->qf = NULL;
g_free(box->ignore_string);
g_free(box->ignore_help);
g_free(box);
cell->cell.gui_private = NULL;
}
@ -276,8 +352,14 @@ xaccClearComboCellMenu (ComboCell * cell)
box->qf = xaccMallocQuickFill();
if (box->item_list != NULL)
{
block_list_signals(cell);
gnc_item_list_clear(box->item_list);
unblock_list_signals(cell);
}
box->list_in_sync = TRUE;
box->list_sorted = TRUE;
}
@ -329,7 +411,15 @@ xaccAddComboCellMenuItem (ComboCell *cell, char * menustr)
gnc_combo_sync_edit_list(box);
if (box->item_list != NULL)
{
block_list_signals(cell);
gnc_item_list_append(box->item_list, menustr);
if (strcmp(menustr, cell->cell.value) == 0)
gnc_item_list_select(box->item_list, menustr);
unblock_list_signals(cell);
}
else
box->list_in_sync = FALSE;
@ -357,7 +447,7 @@ ComboMV (BasicCell *_cell,
int *start_selection,
int *end_selection)
{
QuickFillCell *cell = (QuickFillCell *) _cell;
ComboCell *cell = (ComboCell *) _cell;
PopBox *box = cell->cell.gui_private;
const char *retval;
QuickFill *match;
@ -393,7 +483,11 @@ ComboMV (BasicCell *_cell,
if ((match == NULL) || (match->text == NULL))
{
xaccSetBasicCellValue (_cell, newval);
block_list_signals(cell);
gnc_item_list_select(box->item_list, NULL);
unblock_list_signals(cell);
return newval;
}
@ -416,13 +510,9 @@ ComboMV (BasicCell *_cell,
box->list_popped = TRUE;
}
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
box->select_item_signal);
block_list_signals(cell);
gnc_item_list_select(box->item_list, retval);
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
box->select_item_signal);
unblock_list_signals(cell);
xaccSetBasicCellValue (_cell, retval);
@ -431,6 +521,176 @@ ComboMV (BasicCell *_cell,
/* =============================================== */
static gncBoolean
ComboDirect (BasicCell *bcell,
const char *oldval,
char **newval_ptr,
int *cursor_position,
int *start_selection,
int *end_selection,
void *gui_data)
{
ComboCell *cell = (ComboCell *) bcell;
PopBox *box = cell->cell.gui_private;
GdkEventKey *event = gui_data;
gboolean keep_on_going = FALSE;
gboolean extra_colon;
QuickFill *match;
char *search;
int prefix_len;
int new_pos;
int length;
if (event->type != GDK_KEY_PRESS)
return GNC_F;
length = strlen(oldval);
switch (event->keyval) {
case GDK_slash:
if (!(event->state & GDK_MOD1_MASK))
{
if (event->keyval == box->complete_char)
break;
return GNC_F;
}
keep_on_going = TRUE;
case GDK_Tab:
case GDK_ISO_Left_Tab:
if (!(event->state & GDK_CONTROL_MASK) &&
!keep_on_going)
return GNC_F;
match = xaccGetQuickFillStrLen(box->qf, oldval,
*cursor_position);
if (match == NULL)
return GNC_T;
match = xaccGetQuickFillUniqueLen(match, &prefix_len);
if (match == NULL)
return GNC_T;
if ((match->text != NULL) &&
(strncmp(match->text, oldval, length) == 0) &&
(strcmp(match->text, oldval) != 0))
{
*newval_ptr = strdup(match->text);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);
block_list_signals(cell);
gnc_item_list_select(box->item_list,
*newval_ptr);
unblock_list_signals(cell);
}
*cursor_position += prefix_len;
*start_selection = *cursor_position;
*end_selection = -1;
return GNC_T;
}
if (box->complete_char == 0)
return GNC_F;
if (event->keyval != box->complete_char)
return GNC_F;
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
return GNC_F;
if ((*cursor_position < length) &&
((*end_selection < length) ||
(*cursor_position < *start_selection)))
return GNC_F;
if ((*cursor_position == length) &&
(*start_selection != *end_selection) &&
(*end_selection < length))
return GNC_F;
search = NULL;
if (*cursor_position < length)
search = strchr(oldval + *cursor_position + 1,
box->complete_char);
new_pos = *cursor_position;
if (search != NULL)
{
new_pos = search - oldval;
extra_colon = FALSE;
}
else
{
new_pos = length;
extra_colon = TRUE;
}
match = xaccGetQuickFillStrLen(box->qf, oldval, new_pos);
if (match == NULL)
return GNC_F;
if (extra_colon)
{
match = xaccGetQuickFill(match, box->complete_char);
if (match == NULL)
return GNC_F;
new_pos++;
}
if ((match->text != NULL) &&
(strncmp(match->text, oldval, length) == 0) &&
(strcmp(match->text, oldval) != 0))
{
*newval_ptr = strdup(match->text);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);
block_list_signals(cell);
gnc_item_list_select(box->item_list, *newval_ptr);
unblock_list_signals(cell);
}
*cursor_position = new_pos;
*start_selection = new_pos;
*end_selection = -1;
return GNC_T;
}
/* =============================================== */
static char *
ComboHelpValue(BasicCell *bcell)
{
ComboCell *cell = (ComboCell *) bcell;
PopBox *box = cell->cell.gui_private;
if ((bcell->value != NULL) && (bcell->value[0] != 0))
{
if ((box->ignore_string != NULL) &&
(box->ignore_help != NULL) &&
(safe_strcmp(bcell->value, box->ignore_string) == 0))
return strdup(box->ignore_help);
return strdup(bcell->value);
}
if (bcell->blank_help != NULL)
return strdup(bcell->blank_help);
return NULL;
}
/* =============================================== */
static void
realizeCombo (BasicCell *bcell, void *data, int pixel_width)
{
@ -454,6 +714,8 @@ realizeCombo (BasicCell *bcell, void *data, int pixel_width)
cell->cell.leave_cell = leaveCombo;
cell->cell.destroy = destroyCombo;
cell->cell.modify_verify = ComboMV;
cell->cell.direct_update = ComboDirect;
cell->cell.get_help_value = ComboHelpValue;
}
/* =============================================== */
@ -463,7 +725,7 @@ moveCombo (BasicCell *bcell, int phys_row, int phys_col)
{
PopBox *box = (PopBox *) bcell->gui_private;
disconnect_list_signals((ComboCell *) bcell);
combo_disconnect_signals((ComboCell *) bcell);
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", FALSE, NULL);
@ -476,13 +738,19 @@ moveCombo (BasicCell *bcell, int phys_row, int phys_col)
/* =============================================== */
static const char *
enterCombo (BasicCell *bcell, const char *value,
enterCombo (BasicCell *bcell,
const char *value,
int *cursor_position,
int *start_selection,
int *end_selection)
{
ComboCell *cell = (ComboCell *) bcell;
PopBox *box = (PopBox *) bcell->gui_private;
if ((box->ignore_string != NULL) &&
(safe_strcmp(value, box->ignore_string) == 0))
return strdup(value);
gnc_combo_sync_edit_list(box);
gnc_combo_sort_edit_list(box);
@ -491,9 +759,11 @@ enterCombo (BasicCell *bcell, const char *value,
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", TRUE, NULL);
block_list_signals(cell);
gnc_item_list_select(box->item_list, bcell->value);
unblock_list_signals(cell);
connect_list_signals((ComboCell *) bcell);
combo_connect_signals((ComboCell *) bcell);
*cursor_position = -1;
*start_selection = 0;
@ -511,7 +781,7 @@ leaveCombo (BasicCell *bcell, const char *value)
PopBox *box = (PopBox *) bcell->gui_private;
disconnect_list_signals((ComboCell *) bcell);
combo_disconnect_signals((ComboCell *) bcell);
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", FALSE, NULL);
@ -526,8 +796,10 @@ leaveCombo (BasicCell *bcell, const char *value)
(gpointer) value,
(GCompareFunc) safe_strcmp);
/* hack, "Split" is ok, even though it's not in list */
if (find == NULL && (safe_strcmp(value, "Split") != 0))
/* The ignore string is ok, even if it's not in list. */
if (find == NULL &&
((box->ignore_string == NULL) ||
(safe_strcmp(value, box->ignore_string) != 0)))
return strdup("");
}
@ -549,6 +821,51 @@ xaccComboCellSetStrict (ComboCell *cell, gncBoolean strict)
box->strict = strict;
}
/* =============================================== */
void
xaccComboCellSetCompleteChar (ComboCell *cell, char complete_char)
{
PopBox *box;
if (cell == NULL)
return;
box = (PopBox *) cell->cell.gui_private;
box->complete_char = complete_char;
}
/* =============================================== */
void
xaccComboCellSetIgnoreString (ComboCell *cell, const char *ignore_string)
{
PopBox *box;
if (cell == NULL)
return;
box = (PopBox *) cell->cell.gui_private;
box->ignore_string = g_strdup(ignore_string);
}
/* =============================================== */
void
xaccComboCellSetIgnoreHelp (ComboCell *cell, const char *ignore_help)
{
PopBox *box;
if (cell == NULL)
return;
box = (PopBox *) cell->cell.gui_private;
box->ignore_help = g_strdup(ignore_help);
}
/* =============== end of file =================== */

View File

@ -254,11 +254,10 @@ draw_cell (GnucashGrid *grid, int block,
sheet_block = gnucash_sheet_get_block (grid->sheet, block, 0);
gdk_gc_set_foreground (grid->gc, sheet_block->bg_colors[i][j]);
gdk_draw_rectangle (drawable, grid->gc, TRUE, x, y, width, height);
gdk_gc_set_foreground (grid->gc, &gn_black);
/* draw the border */
gdk_draw_rectangle (drawable, grid->gc, FALSE, x, y, width, height);
@ -268,10 +267,9 @@ draw_cell (GnucashGrid *grid, int block,
font = style->fonts[i][j];
else
font = grid->normal_font;
gdk_gc_set_foreground (grid->gc, &gn_black);
gdk_gc_set_foreground (grid->gc, sheet_block->fg_colors[i][j]);
if (table->current_cursor_virt_row == block &&
(!text || strlen(text) == 0)) {
font = grid->italic_font;

View File

@ -60,28 +60,35 @@ gnucash_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
{
GnucashHeader *header = GNUCASH_HEADER(item);
SheetBlockStyle *style = header->style;
SheetBlockStyle *header_style;
int i, j;
int xpaint, ypaint;
int w = 0, h = 0;
gchar *text;
GdkFont *font;
gdk_gc_set_foreground(header->gc, &gn_white);
header_style = header->sheet->cursor_style[GNUCASH_CURSOR_HEADER];
/* Assume all cells have the same color */
gdk_gc_set_foreground(header->gc,
header_style->inactive_bg_color[0][0]);
gdk_draw_rectangle(drawable, header->gc, TRUE, 0, 0, width, height);
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, -1, -1);
gdk_gc_set_foreground (header->gc, &gn_black);
gdk_draw_rectangle (drawable, header->gc, FALSE,
-x, -y, style->dimensions->width-1, style->dimensions->height);
gdk_draw_line (drawable, header->gc,
-x, style->dimensions->height-1, style->dimensions->width-1, style->dimensions->height-1);
gdk_draw_rectangle (drawable, header->gc, FALSE, -x, -y,
style->dimensions->width,
style->dimensions->height);
gdk_draw_line (drawable, header->gc, -x,
style->dimensions->height - 1,
style->dimensions->width - 1,
style->dimensions->height - 1);
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, -1, -1);
gdk_gc_set_background (header->gc, &gn_white);
gdk_gc_set_foreground (header->gc, &gn_black);
font = style->header_font;
ypaint = -y;
for (i = 0; i < style->nrows; i++) {
@ -185,8 +192,13 @@ gnucash_header_unrealize (GnomeCanvasItem *item)
header->gc = NULL;
}
gdk_cursor_destroy (header->resize_cursor);
gdk_cursor_destroy (header->normal_cursor);
if (header->resize_cursor != NULL)
gdk_cursor_destroy (header->resize_cursor);
header->resize_cursor = NULL;
if (header->normal_cursor != NULL)
gdk_cursor_destroy (header->normal_cursor);
header->normal_cursor = NULL;
if (GNOME_CANVAS_ITEM_CLASS (gnucash_header_parent_class)->unrealize)
(*GNOME_CANVAS_ITEM_CLASS
@ -200,15 +212,14 @@ gnucash_header_destroy (GtkObject *object)
if (GTK_OBJECT_CLASS (gnucash_header_parent_class)->destroy)
(*GTK_OBJECT_CLASS
(gnucash_header_parent_class)->destroy)(object);
}
void
gnucash_header_reconfigure (GnucashHeader *header)
{
GnomeCanvas *canvas = GNOME_CANVAS_ITEM(header)->canvas;
int w, h;
double old_w, old_h;
int w, h;
header->style = header->sheet->cursor_style[header->type];
@ -245,23 +256,30 @@ gnucash_header_point (GnomeCanvasItem *item,
}
/*
* Returns -1 if pointer not on a resize line, else returns
* the index of the column to the left.
* Returns FALSE if pointer not on a resize line, else returns
* TRUE. Returns the index of the column to the left in the col
* argument.
*/
static int
pointer_on_resize_line (GnucashHeader *header, int x, int y)
static gboolean
pointer_on_resize_line (GnucashHeader *header, int x, int y, int *col)
{
SheetBlockStyle *style = header->style;
gboolean on_the_line = FALSE;
int pixels = 0; /* = style->dimensions->pixel_widths[header->row][0];*/
int j;
int pixels = style->dimensions->pixel_widths[header->row][0];
for (j = 1; j < style->ncols; j++) {
if (x >= pixels - 1 && x <= pixels+1)
return j-1;
for (j = 0; j < style->ncols; j++) {
pixels += style->dimensions->pixel_widths[header->row][j];
if (x >= pixels - 1 && x <= pixels + 1)
on_the_line = TRUE;
if (x <= pixels + 1)
break;
}
return -1;
if (col != NULL)
*col = j;
return on_the_line;
}
@ -275,7 +293,8 @@ find_resize_col (GnucashHeader *header, int col)
return -1;
/* skip to the right over zero-width columns */
while (col+1 < style->ncols && style->dimensions->pixel_widths[0][col+1] == 0)
while (col+1 < style->ncols &&
style->dimensions->pixel_widths[0][col+1] == 0)
col++;
/* now go back left till we have a resizable column */
@ -286,11 +305,30 @@ find_resize_col (GnucashHeader *header, int col)
col--;
}
/* didn't find a resizable column to the right of col */
/* didn't find a resizable column to the right of col */
return -1;
}
static void
gnucash_header_auto_resize_column (GnucashHeader *header, gint col)
{
GnucashSheet *sheet = header->sheet;
int width = gnucash_sheet_col_max_width (sheet, 0, col);
gnucash_sheet_style_set_col_width (sheet, header->style,
col, width, FALSE);
gnucash_sheet_style_set_dimensions (sheet, header->style);
gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
item_edit_configure (ITEM_EDIT(sheet->item_editor));
gnucash_sheet_update_adjustments (sheet);
gnucash_header_request_redraw (header);
gnucash_sheet_redraw_all (sheet);
}
static gint
gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
@ -300,7 +338,6 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
int x, y;
int col;
switch (event->type) {
case GDK_MOTION_NOTIFY:
@ -321,7 +358,7 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
}
new_width = header->resize_col_width + change;
if (new_width >= 0) {
header->resize_x = x;
header->resize_col_width = new_width;
@ -330,10 +367,9 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
break;
}
if ((col = pointer_on_resize_line(header, x, y)) > -1 &&
gnucash_style_col_is_resizable (header->style, col) )
if (pointer_on_resize_line(header, x, y, &col) &&
gnucash_style_col_is_resizable (header->style, col))
gdk_window_set_cursor (GTK_WIDGET(canvas)->window,
header->resize_cursor);
else
@ -344,13 +380,18 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
case GDK_BUTTON_PRESS:
{
int col;
if (event->button.button != 1)
break;
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
&x, &y);
col = pointer_on_resize_line (header, x, y);
col = find_resize_col (header, col);
if (pointer_on_resize_line (header, x, y, &col))
col = find_resize_col (header, col);
else
col = -1;
if (col > -1) {
header->in_resize = TRUE;
header->resize_col = col;
@ -363,7 +404,10 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
case GDK_BUTTON_RELEASE:
{
GnucashSheet *sheet = header->sheet;
if (event->button.button != 1)
break;
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
&x, &y);
@ -371,31 +415,59 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
if (header->needs_ungrab) {
gnome_canvas_item_ungrab (item, event->button.time);
header->needs_ungrab = FALSE;
gnucash_sheet_style_set_col_width (sheet, header->style,
header->resize_col, header->resize_col_width, FALSE);
gnucash_sheet_style_set_dimensions (sheet, header->style);
gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
item_edit_configure (ITEM_EDIT(sheet->item_editor));
gnucash_sheet_update_adjustments (sheet);
gnucash_header_request_redraw (header);
gnucash_sheet_redraw_all (sheet);
}
gnucash_sheet_style_set_col_width (sheet, header->style,
header->resize_col, header->resize_col_width, TRUE);
gnucash_sheet_style_set_dimensions (sheet, header->style);
header->in_resize = FALSE;
header->resize_col = -1;
gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
item_edit_configure (ITEM_EDIT(sheet->item_editor));
gnucash_sheet_update_adjustments (sheet);
gnucash_header_request_redraw (header);
gnucash_sheet_redraw_all (sheet);
}
break;
}
case GDK_2BUTTON_PRESS:
{
gboolean on_line;
int ptr_col;
int resize_col;
if (event->button.button != 1)
break;
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
&x, &y);
on_line = pointer_on_resize_line (header, x, y, &ptr_col);
resize_col = find_resize_col (header, ptr_col);
if ((resize_col > -1) &&
(on_line || (resize_col == ptr_col))) {
header->in_resize = FALSE;
header->resize_col = -1;
if (header->needs_ungrab) {
gnome_canvas_item_ungrab (item, event->button.time);
header->needs_ungrab = FALSE;
}
gnucash_header_auto_resize_column (header, resize_col);
}
}
break;
default:
break;
}
return TRUE;
}
@ -441,7 +513,7 @@ gnucash_header_init (GnucashHeader *header)
header->in_resize = FALSE;
header->resize_col = -1;
header->resize_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
header->normal_cursor = gdk_cursor_new (GDK_X_CURSOR);
header->normal_cursor = NULL;
}

View File

@ -40,7 +40,7 @@ typedef struct {
int resize_x;
int resize_col;
int needs_ungrab;
GdkGC *gc;
GdkCursor *normal_cursor;
GdkCursor *resize_cursor;

View File

@ -28,7 +28,25 @@
#include "util.h"
/* The arguments we take */
enum {
ARG_0,
ARG_SHEET, /* The Sheet argument */
ARG_GTK_ENTRY, /* The GtkEntry argument */
ARG_IS_COMBO, /* Should this be a combo? */
};
/* values for selection info */
enum {
TARGET_STRING,
TARGET_TEXT,
TARGET_COMPOUND_TEXT
};
static GnomeCanvasItemClass *item_edit_parent_class;
static GdkAtom clipboard_atom = GDK_NONE;
static GdkAtom ctext_atom = GDK_NONE;
typedef struct _TextDrawInfo TextDrawInfo;
struct _TextDrawInfo
@ -63,15 +81,6 @@ struct _TextDrawInfo
};
/* The arguments we take */
enum {
ARG_0,
ARG_SHEET, /* The Sheet argument */
ARG_GTK_ENTRY, /* The GtkEntry argument */
ARG_IS_COMBO, /* Should this be a combo? */
};
static void item_edit_show_combo_toggle (ItemEdit *item_edit,
gint x, gint y,
gint width, gint height,
@ -364,6 +373,10 @@ item_edit_init (ItemEdit *item_edit)
item_edit->editor = NULL;
item_edit->clipboard = NULL;
item_edit->has_selection = FALSE;
item_edit->is_combo = FALSE;
item_edit->show_list = FALSE;
item_edit->combo_toggle.combo_button = NULL;
item_edit->combo_toggle.combo_button_item = NULL;
item_edit->combo_toggle.toggle_offset = 0;
@ -393,6 +406,14 @@ queue_sync (ItemEdit *item_edit)
gnome_canvas_request_redraw (canvas, x, y, x+w, y+h);
}
void
item_edit_redraw (ItemEdit *item_edit)
{
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
queue_sync(item_edit);
}
static void
entry_changed (GtkEntry *entry, void *data)
@ -584,8 +605,42 @@ item_edit_configure (ItemEdit *item_edit)
}
void
item_edit_claim_selection (ItemEdit *item_edit, guint32 time)
{
GtkEditable *editable;
gint start_sel, end_sel;
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
editable = GTK_EDITABLE (item_edit->editor);
start_sel = MIN(editable->selection_start_pos,
editable->selection_end_pos);
end_sel = MAX(editable->selection_start_pos,
editable->selection_end_pos);
if (start_sel != end_sel)
{
gtk_selection_owner_set (GTK_WIDGET(item_edit->sheet),
GDK_SELECTION_PRIMARY, time);
item_edit->has_selection = TRUE;
}
else
{
GdkWindow *owner;
owner = gdk_selection_owner_get (GDK_SELECTION_PRIMARY);
if (owner == GTK_WIDGET(item_edit->sheet)->window)
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
item_edit->has_selection = FALSE;
}
}
static void
item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
item_edit_cut_copy_clipboard (ItemEdit *item_edit, guint32 time, gboolean cut)
{
GtkEditable *editable;
gint start_sel, end_sel;
@ -604,10 +659,14 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
if (start_sel == end_sel)
return;
if (item_edit->clipboard != NULL)
g_free(item_edit->clipboard);
g_free(item_edit->clipboard);
if (gtk_selection_owner_set (GTK_WIDGET(item_edit->sheet),
clipboard_atom, time))
clip = gtk_editable_get_chars (editable, start_sel, end_sel);
else
clip = NULL;
clip = gtk_editable_get_chars(editable, start_sel, end_sel);
item_edit->clipboard = clip;
if (!cut)
@ -620,53 +679,44 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
void
item_edit_cut_clipboard (ItemEdit *item_edit)
item_edit_cut_clipboard (ItemEdit *item_edit, guint32 time)
{
item_edit_cut_copy_clipboard(item_edit, TRUE);
item_edit_cut_copy_clipboard(item_edit, time, TRUE);
}
void
item_edit_copy_clipboard (ItemEdit *item_edit)
item_edit_copy_clipboard (ItemEdit *item_edit, guint32 time)
{
item_edit_cut_copy_clipboard(item_edit, FALSE);
item_edit_cut_copy_clipboard(item_edit, time, FALSE);
}
void
item_edit_paste_clipboard (ItemEdit *item_edit)
item_edit_paste_clipboard (ItemEdit *item_edit, guint32 time)
{
GtkEditable *editable;
gint start_sel, end_sel;
gint current_pos;
gchar *clip;
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
if ((item_edit->clipboard == NULL) ||
(item_edit->clipboard[0] == 0))
return;
if (ctext_atom == GDK_NONE)
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
editable = GTK_EDITABLE (item_edit->editor);
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
clipboard_atom, ctext_atom, time);
}
current_pos = editable->current_pos;
start_sel = MIN(editable->selection_start_pos,
editable->selection_end_pos);
end_sel = MAX(editable->selection_start_pos,
editable->selection_end_pos);
if (start_sel != end_sel)
{
gtk_editable_delete_text(editable, start_sel, end_sel);
current_pos = start_sel;
}
void
item_edit_paste_primary (ItemEdit *item_edit, guint32 time)
{
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
clip = item_edit->clipboard;
gtk_editable_insert_text(editable, clip, strlen(clip), &current_pos);
if (ctext_atom == GDK_NONE)
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
gtk_editable_select_region(editable, 0, 0);
gtk_editable_set_position(editable, current_pos);
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
GDK_SELECTION_PRIMARY, ctext_atom, time);
}
@ -871,6 +921,7 @@ item_edit_class_init (ItemEditClass *item_edit_class)
item_class->realize = item_edit_realize;
}
GtkType
item_edit_get_type (void)
{
@ -921,6 +972,13 @@ create_combo_toggle(GnomeCanvasGroup *parent, ComboToggle *ct)
GnomeCanvasItem *
item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry)
{
static const GtkTargetEntry targets[] = {
{ "STRING", 0, TARGET_STRING },
{ "TEXT", 0, TARGET_TEXT },
{ "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
};
static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
GnomeCanvasItem *item;
ItemEdit *item_edit;
@ -936,6 +994,17 @@ item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry)
create_combo_toggle(parent, &item_edit->combo_toggle);
if (clipboard_atom == GDK_NONE)
clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
gtk_selection_add_targets (GTK_WIDGET(sheet),
GDK_SELECTION_PRIMARY,
targets, n_targets);
gtk_selection_add_targets (GTK_WIDGET(sheet),
clipboard_atom,
targets, n_targets);
return item;
}
@ -1046,6 +1115,216 @@ item_edit_set_list (ItemEdit *item_edit, GNCItemList *item_list)
item_edit_update (GNOME_CANVAS_ITEM(item_edit), NULL, NULL, 0);
}
void
item_edit_set_has_selection (ItemEdit *item_edit, gboolean has_selection)
{
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
item_edit->has_selection = has_selection;
}
gboolean
item_edit_selection_clear (ItemEdit *item_edit,
GdkEventSelection *event)
{
g_return_val_if_fail(item_edit != NULL, FALSE);
g_return_val_if_fail(IS_ITEM_EDIT(item_edit), FALSE);
g_return_val_if_fail(event != NULL, FALSE);
/* Let the selection handling code know that the selection
* has been changed, since we've overriden the default handler */
if (!gtk_selection_clear(GTK_WIDGET(item_edit->sheet), event))
return FALSE;
if (event->selection == GDK_SELECTION_PRIMARY)
{
if (item_edit->has_selection)
{
item_edit->has_selection = FALSE;
/* TODO: redraw differently? */
}
}
else if (event->selection == clipboard_atom)
{
g_free(item_edit->clipboard);
item_edit->clipboard = NULL;
}
return TRUE;
}
void
item_edit_selection_get (ItemEdit *item_edit,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GtkEditable *editable;
gint start_pos;
gint end_pos;
gchar *str;
gint length;
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
editable = GTK_EDITABLE (item_edit->editor);
if (selection_data->selection == GDK_SELECTION_PRIMARY)
{
start_pos = MIN(editable->selection_start_pos,
editable->selection_end_pos);
end_pos = MAX(editable->selection_start_pos,
editable->selection_end_pos);
str = gtk_editable_get_chars(editable, start_pos, end_pos);
}
else /* CLIPBOARD */
str = item_edit->clipboard;
if (str == NULL)
return;
length = strlen(str);
if (info == TARGET_STRING)
{
gtk_selection_data_set (selection_data,
GDK_SELECTION_TYPE_STRING,
8 * sizeof(gchar), (guchar *) str,
length);
}
else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
{
guchar *text;
gchar c;
GdkAtom encoding;
gint format;
gint new_length;
c = str[length];
str[length] = '\0';
gdk_string_to_compound_text(str, &encoding, &format,
&text, &new_length);
gtk_selection_data_set(selection_data, encoding,
format, text, new_length);
gdk_free_compound_text(text);
str[length] = c;
}
if (str != item_edit->clipboard)
g_free(str);
}
void
item_edit_selection_received (ItemEdit *item_edit,
GtkSelectionData *selection_data,
guint time)
{
GtkEditable *editable;
gboolean reselect;
gint old_pos;
gint tmp_pos;
enum {INVALID, STRING, CTEXT} type;
g_return_if_fail(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit));
editable = GTK_EDITABLE(item_edit->editor);
if (selection_data->type == GDK_TARGET_STRING)
type = STRING;
else if ((selection_data->type ==
gdk_atom_intern("COMPOUND_TEXT", FALSE)) ||
(selection_data->type == gdk_atom_intern("TEXT", FALSE)))
type = CTEXT;
else
type = INVALID;
if (type == INVALID || selection_data->length < 0)
{
/* avoid infinite loop */
if (selection_data->target != GDK_TARGET_STRING)
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
selection_data->selection,
GDK_TARGET_STRING, time);
return;
}
reselect = FALSE;
if ((editable->selection_start_pos != editable->selection_end_pos) &&
(!item_edit->has_selection ||
(selection_data->selection == clipboard_atom)))
{
reselect = TRUE;
gtk_editable_delete_text(editable,
MIN(editable->selection_start_pos,
editable->selection_end_pos),
MAX(editable->selection_start_pos,
editable->selection_end_pos));
}
tmp_pos = old_pos = editable->current_pos;
switch (type)
{
case STRING:
selection_data->data[selection_data->length] = 0;
gtk_editable_insert_text
(editable, (gchar *) selection_data->data,
strlen((gchar *)selection_data->data),
&tmp_pos);
gtk_editable_set_position(editable, tmp_pos);
break;
case CTEXT: {
gchar **list;
gint count;
gint i;
count = gdk_text_property_to_text_list
(selection_data->type, selection_data->format,
selection_data->data, selection_data->length,
&list);
for (i = 0; i < count; i++)
{
gtk_editable_insert_text(editable,
list[i],
strlen(list[i]),
&tmp_pos);
gtk_editable_set_position(editable, tmp_pos);
}
if (count > 0)
gdk_free_text_list(list);
}
break;
case INVALID: /* quiet compiler */
break;
}
if (!reselect)
return;
gtk_editable_select_region(editable, old_pos, editable->current_pos);
}
/*
Local Variables:
c-basic-offset: 8

View File

@ -63,6 +63,7 @@ typedef struct
guint signal; /* the signal we connect */
guint signal2; /* the other signal we connect */
gboolean has_selection;
gboolean is_combo;
gboolean show_list;
@ -101,9 +102,28 @@ gboolean item_edit_set_cursor_pos (ItemEdit *item_edit,
gboolean changed_cells,
gboolean extend_selection);
void item_edit_cut_clipboard (ItemEdit *item_edit);
void item_edit_copy_clipboard (ItemEdit *item_edit);
void item_edit_paste_clipboard (ItemEdit *item_edit);
void item_edit_redraw (ItemEdit *item_edit);
void item_edit_claim_selection (ItemEdit *item_edit, guint32 time);
void item_edit_cut_clipboard (ItemEdit *item_edit, guint32 time);
void item_edit_copy_clipboard (ItemEdit *item_edit, guint32 time);
void item_edit_paste_clipboard (ItemEdit *item_edit, guint32 time);
void item_edit_paste_primary (ItemEdit *item_edit, guint32 time);
void item_edit_set_has_selection (ItemEdit *item_edit, gboolean has_selection);
gboolean item_edit_selection_clear (ItemEdit *item_edit,
GdkEventSelection *event);
void item_edit_selection_get (ItemEdit *item_edit,
GtkSelectionData *selection_data,
guint info,
guint time);
void item_edit_selection_received (ItemEdit *item_edit,
GtkSelectionData *selection_data,
guint time);
typedef struct {
GnomeCanvasItemClass parent_class;

View File

@ -28,6 +28,7 @@
enum
{
SELECT_ITEM,
CHANGE_ITEM,
KEY_PRESS_EVENT,
LAST_SIGNAL
};
@ -144,19 +145,64 @@ gnc_item_list_button_event(GtkWidget *widget, GdkEventButton *event,
}
static gboolean
gnc_clist_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
GtkAdjustment *vadj;
gfloat multiplier = 1.0;
gfloat v_value;
vadj = gtk_clist_get_vadjustment(GTK_CLIST(widget));
v_value = vadj->value;
if (event->state & GDK_SHIFT_MASK)
multiplier = 5.0;
switch (event->button)
{
case 4:
v_value -= vadj->step_increment * multiplier;
break;
case 5:
v_value += vadj->step_increment * multiplier;
break;
default:
return FALSE;
}
v_value = CLAMP(v_value, vadj->lower, vadj->upper - vadj->page_size);
gtk_adjustment_set_value(vadj, v_value);
return FALSE;
}
static gboolean
gnc_item_list_key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
GNCItemList *item_list = GNC_ITEM_LIST(data);
GtkCList *clist;
gboolean got_text;
gchar *string;
gint row;
switch (event->keyval) {
case GDK_space:
if (event->state & GDK_CONTROL_MASK)
{
event->state &= ~GDK_CONTROL_MASK;
case GDK_Return:
clist = item_list->clist;
row = clist->focus_row;
if (row < 0)
return FALSE;
}
break;
got_text = gtk_clist_get_text(clist, row, 0, &string);
if (!got_text)
return FALSE;
gtk_signal_emit(GTK_OBJECT(item_list),
gnc_item_list_signals[SELECT_ITEM],
string);
return TRUE;
case GDK_Page_Up:
case GDK_Page_Down:
case GDK_Up:
@ -197,6 +243,16 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gnc_item_list_signals[CHANGE_ITEM] =
gtk_signal_new("change_item",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET(GNCItemListClass,
change_item),
gtk_marshal_NONE__POINTER,
GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gnc_item_list_signals[KEY_PRESS_EVENT] =
gtk_signal_new ("key_press_event",
GTK_RUN_LAST,
@ -210,6 +266,10 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
gtk_object_class_add_signals(object_class,
gnc_item_list_signals,
LAST_SIGNAL);
item_list_class->select_item = NULL;
item_list_class->change_item = NULL;
item_list_class->key_press_event = NULL;
}
@ -249,13 +309,17 @@ clist_select_row_cb(GtkCList *clist, gint row, gint column,
gboolean got_text;
char *string;
got_text = gtk_clist_get_text(clist, row, column, &string);
got_text = gtk_clist_get_text(clist, row, 0, &string);
if (!got_text)
return;
gtk_signal_emit(GTK_OBJECT(item_list),
gnc_item_list_signals[SELECT_ITEM], string);
if (column < 0)
gtk_signal_emit(GTK_OBJECT(item_list),
gnc_item_list_signals[CHANGE_ITEM], string);
else
gtk_signal_emit(GTK_OBJECT(item_list),
gnc_item_list_signals[SELECT_ITEM], string);
}
@ -271,6 +335,7 @@ gnc_item_list_new(GnomeCanvasGroup *parent)
clist = gtk_clist_new(1);
gtk_box_pack_start(GTK_BOX(hbox), clist, TRUE, TRUE, 0);
gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_BROWSE);
scrollbar = gtk_vscrollbar_new(NULL);
gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0);
@ -290,7 +355,11 @@ gnc_item_list_new(GnomeCanvasGroup *parent)
gtk_signal_connect_after(GTK_OBJECT(hbox), "button_press_event",
GTK_SIGNAL_FUNC(gnc_item_list_button_event),
NULL);
(gpointer) item_list);
gtk_signal_connect(GTK_OBJECT(clist), "button_press_event",
GTK_SIGNAL_FUNC(gnc_clist_button_event),
(gpointer) item_list);
gtk_signal_connect(GTK_OBJECT(clist), "key_press_event",
GTK_SIGNAL_FUNC(gnc_item_list_key_event),

View File

@ -57,6 +57,9 @@ typedef struct
void (*select_item) (GNCItemList *item_list,
char *item_string);
void (*change_item) (GNCItemList *item_list,
char *item_string);
void (*key_press_event) (GNCItemList *item_list,
GdkEventKey *event);

View File

@ -36,8 +36,8 @@
#define DEFAULT_REGISTER_HEIGHT 400
#define DEFAULT_REGISTER_WIDTH 630
#define DEFAULT_REGISTER_ROWS 15
static guint gnucash_register_initial_rows = 15;
static void gnucash_sheet_cell_set_from_table (GnucashSheet *sheet,
gint virt_row, gint virt_col,
@ -72,6 +72,12 @@ static GtkTableClass *register_parent_class;
static guint register_signals[LAST_SIGNAL];
void
gnucash_register_set_initial_rows(guint num_rows)
{
gnucash_register_initial_rows = num_rows;
}
gint
gnucash_sheet_cell_valid (GnucashSheet *sheet, gint virt_row, gint virt_col,
gint cell_row, gint cell_col)
@ -161,7 +167,6 @@ gnucash_sheet_cursor_set_from_table (GnucashSheet *sheet, gncBoolean do_scroll)
table->current_cursor_virt_col,
cell_row,
cell_col);
}
@ -393,7 +398,6 @@ gnucash_sheet_block_pixel_origin (GnucashSheet *sheet, gint vrow, gint vcol,
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUCASH_IS_SHEET(sheet));
if ( vrow <= 0 || vrow > sheet->num_virt_rows ||
vcol < 0 || vcol > sheet->num_virt_cols)
return;
@ -796,18 +800,18 @@ compute_optimal_width (GnucashSheet *sheet)
{
SheetBlockStyle *style;
if (sheet->default_width >= 0)
return sheet->default_width;
if ((sheet == NULL) || (sheet->cursor_style == NULL))
return DEFAULT_REGISTER_WIDTH;
if (sheet->default_width >= 0)
return sheet->default_width;
style = sheet->cursor_style[GNUCASH_CURSOR_HEADER];
if ((style == NULL) || (style->widths == NULL))
return DEFAULT_REGISTER_WIDTH;
sheet->default_width = gnucash_style_default_width(sheet, style);
sheet->default_width = gnucash_style_default_width (sheet, style);
return sheet->default_width;
}
@ -832,7 +836,7 @@ compute_optimal_height (GnucashSheet *sheet)
return DEFAULT_REGISTER_HEIGHT;
row_height = style->dimensions->pixel_heights[0][0];
sheet->default_height = row_height * DEFAULT_REGISTER_ROWS;
sheet->default_height = row_height * gnucash_register_initial_rows;
return sheet->default_height;
}
@ -1049,6 +1053,9 @@ gnucash_sheet_delete_cb (GtkWidget *widget,
int cursor_position = start_pos;
int start_sel, end_sel;
if (end_pos <= start_pos)
return;
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
&p_row, &p_col);
gnucash_cursor_get_virt (GNUCASH_CURSOR (sheet->cursor),
@ -1171,7 +1178,7 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
sheet->insert_signal =
gtk_signal_connect(GTK_OBJECT(sheet->entry), "insert_text",
GTK_SIGNAL_FUNC(gnucash_sheet_insert_cb),
sheet);
sheet);
sheet->delete_signal =
gtk_signal_connect(GTK_OBJECT(sheet->entry), "delete_text",
@ -1179,8 +1186,6 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
sheet);
}
static gboolean dragging = FALSE;
static gboolean
gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
{
@ -1194,14 +1199,20 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
sheet = GNUCASH_SHEET(widget);
if (!dragging || !sheet->editing || event->type != GDK_MOTION_NOTIFY)
if (!(event->state & GDK_BUTTON1_MASK) && sheet->grabbed)
{
gtk_grab_remove (widget);
sheet->grabbed = FALSE;
}
if (sheet->button != 1)
return FALSE;
if (!sheet->editing || event->type != GDK_MOTION_NOTIFY)
return FALSE;
if (!(event->state & GDK_BUTTON1_MASK))
{
dragging = FALSE;
return FALSE;
}
gnome_canvas_get_scroll_offsets (GNOME_CANVAS(sheet),
&xoffset, &yoffset);
@ -1221,14 +1232,28 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
static gboolean
gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event)
{
GnucashSheet *sheet;
g_return_val_if_fail(widget != NULL, TRUE);
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE);
g_return_val_if_fail(event != NULL, TRUE);
sheet = GNUCASH_SHEET (widget);
if (sheet->button != event->button)
return FALSE;
sheet->button = 0;
if (event->button != 1)
return FALSE;
dragging = FALSE;
gtk_grab_remove (widget);
sheet->grabbed = FALSE;
item_edit_set_has_selection(ITEM_EDIT(sheet->item_editor), FALSE);
item_edit_claim_selection(ITEM_EDIT(sheet->item_editor), event->time);
return TRUE;
}
@ -1236,30 +1261,49 @@ gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event)
static void
gnucash_sheet_scroll_event(GnucashSheet *sheet, GdkEventButton *event)
{
GtkAdjustment *vadj;
gfloat multiplier = 1.0;
gfloat v_value;
GtkAdjustment *vadj;
gfloat multiplier = 1.0;
gfloat v_value;
vadj = sheet->vadj;
v_value = vadj->value;
if (event->state & GDK_SHIFT_MASK)
multiplier = 5.0;
vadj = sheet->vadj;
v_value = vadj->value;
if (event->state & GDK_SHIFT_MASK)
multiplier = 5.0;
switch (event->button)
{
case 4:
v_value -= vadj->step_increment * multiplier;
break;
case 5:
v_value += vadj->step_increment * multiplier;
break;
default:
return;
}
switch (event->button)
{
case 4:
v_value -= vadj->step_increment * multiplier;
break;
case 5:
v_value += vadj->step_increment * multiplier;
break;
default:
return;
}
v_value = CLAMP(v_value, vadj->lower, vadj->upper - vadj->page_size);
v_value = CLAMP(v_value, vadj->lower, vadj->upper - vadj->page_size);
gtk_adjustment_set_value(vadj, v_value);
gtk_adjustment_set_value(vadj, v_value);
}
static void
gnucash_sheet_check_grab (GnucashSheet *sheet)
{
GdkModifierType mods;
if (!sheet->grabbed)
return;
gdk_input_window_get_pointer(GTK_WIDGET(sheet)->window,
GDK_CORE_POINTER, NULL, NULL,
NULL, NULL, NULL, &mods);
if (!(mods & GDK_BUTTON1_MASK))
{
gtk_grab_remove (GTK_WIDGET(sheet));
sheet->grabbed = FALSE;
}
}
static gboolean
@ -1286,11 +1330,24 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
sheet = GNUCASH_SHEET (widget);
table = sheet->table;
if (sheet->button && (sheet->button != event->button))
return FALSE;
sheet->button = event->button;
if (!GTK_WIDGET_HAS_FOCUS(widget))
gtk_widget_grab_focus(widget);
switch (event->button)
{
case 1:
break;
case 2:
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
item_edit_paste_primary(ITEM_EDIT(sheet->item_editor),
event->time);
return TRUE;
case 3:
return FALSE;
case 4:
@ -1332,13 +1389,19 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
gtk_editable_set_position(GTK_EDITABLE(sheet->entry), -1);
gtk_editable_select_region(GTK_EDITABLE(sheet->entry), 0, -1);
item_edit_claim_selection (ITEM_EDIT(sheet->item_editor),
event->time);
return TRUE;
}
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
dragging = TRUE;
gtk_grab_add(widget);
sheet->grabbed = TRUE;
item_edit_set_has_selection(ITEM_EDIT(sheet->item_editor), TRUE);
if ((new_p_row == current_p_row) && (new_p_col == current_p_col) &&
sheet->editing)
@ -1359,11 +1422,18 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
GNC_TABLE_TRAVERSE_POINTER,
&new_p_row, &new_p_col);
gnucash_sheet_check_grab(sheet);
if (exit_register)
return TRUE;
changed_cells = gnucash_sheet_cursor_move(sheet, new_p_row, new_p_col);
gnucash_sheet_check_grab(sheet);
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
&new_p_row, &new_p_col);
item_edit_set_cursor_pos (ITEM_EDIT(sheet->item_editor),
new_p_row, new_p_col, x,
changed_cells, FALSE);
@ -1371,20 +1441,67 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
return TRUE;
}
void
gnucash_register_cut_clipboard (GnucashRegister *reg)
{
GnucashSheet *sheet;
ItemEdit *item_edit;
g_return_if_fail(reg != NULL);
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
sheet = GNUCASH_SHEET(reg->sheet);
item_edit = ITEM_EDIT(sheet->item_editor);
item_edit_cut_clipboard(item_edit, GDK_CURRENT_TIME);
}
void
gnucash_register_copy_clipboard (GnucashRegister *reg)
{
GnucashSheet *sheet;
ItemEdit *item_edit;
g_return_if_fail(reg != NULL);
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
sheet = GNUCASH_SHEET(reg->sheet);
item_edit = ITEM_EDIT(sheet->item_editor);
item_edit_copy_clipboard(item_edit, GDK_CURRENT_TIME);
}
void
gnucash_register_paste_clipboard (GnucashRegister *reg)
{
GnucashSheet *sheet;
ItemEdit *item_edit;
g_return_if_fail(reg != NULL);
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
sheet = GNUCASH_SHEET(reg->sheet);
item_edit = ITEM_EDIT(sheet->item_editor);
item_edit_paste_clipboard(item_edit, GDK_CURRENT_TIME);
}
static gboolean
gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
{
ItemEdit *item_edit;
gboolean handled = FALSE;
guint32 time;
item_edit = ITEM_EDIT(sheet->item_editor);
time = event->time;
switch (event->keyval) {
case GDK_C:
case GDK_c:
if (event->state & GDK_CONTROL_MASK)
{
item_edit_copy_clipboard(item_edit);
item_edit_copy_clipboard(item_edit, time);
handled = TRUE;
}
break;
@ -1392,7 +1509,7 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
case GDK_x:
if (event->state & GDK_CONTROL_MASK)
{
item_edit_cut_clipboard(item_edit);
item_edit_cut_clipboard(item_edit, time);
handled = TRUE;
}
break;
@ -1400,19 +1517,19 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
case GDK_v:
if (event->state & GDK_CONTROL_MASK)
{
item_edit_paste_clipboard(item_edit);
item_edit_paste_clipboard(item_edit, time);
handled = TRUE;
}
break;
case GDK_Insert:
if (event->state & GDK_SHIFT_MASK)
{
item_edit_paste_clipboard(item_edit);
item_edit_paste_clipboard(item_edit, time);
handled = TRUE;
}
else if (event->state & GDK_CONTROL_MASK)
{
item_edit_copy_clipboard(item_edit);
item_edit_copy_clipboard(item_edit, time);
handled = TRUE;
}
break;
@ -1421,6 +1538,97 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
return handled;
}
static gncBoolean
gnucash_sheet_direct_event(GnucashSheet *sheet, GdkEvent *event)
{
GtkEditable *editable;
Table *table = sheet->table;
int v_row, v_col, c_row, c_col;
int p_row, p_col;
gncBoolean result;
gboolean changed;
const char *old_text;
char *new_text;
int cursor_position, start_sel, end_sel;
int new_position, new_start, new_end;
gnucash_cursor_get_phys(GNUCASH_CURSOR(sheet->cursor), &p_row, &p_col);
gnucash_cursor_get_virt(GNUCASH_CURSOR(sheet->cursor),
&v_row, &v_col, &c_row, &c_col);
if (!gnc_register_cell_valid (table, p_row, p_col, GNC_T))
return GNC_F;
old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
if (old_text == NULL)
old_text = "";
new_text = (char *) old_text;
editable = GTK_EDITABLE(sheet->entry);
cursor_position = editable->current_pos;
start_sel = MIN(editable->selection_start_pos,
editable->selection_end_pos);
end_sel = MAX(editable->selection_start_pos,
editable->selection_end_pos);
new_position = cursor_position;
new_start = start_sel;
new_end = end_sel;
result = gnc_table_direct_update(table,
p_row, p_col,
old_text, &new_text,
&new_position,
&new_start, &new_end,
event);
gnucash_sheet_cell_set_from_table (sheet, v_row, v_col, c_row, c_col);
changed = FALSE;
if ((new_text != old_text) && new_text != NULL)
{
gtk_signal_handler_block (GTK_OBJECT (sheet->entry),
sheet->insert_signal);
gtk_signal_handler_block (GTK_OBJECT (sheet->entry),
sheet->delete_signal);
gtk_entry_set_text (GTK_ENTRY (sheet->entry), new_text);
gtk_signal_handler_unblock (GTK_OBJECT (sheet->entry),
sheet->delete_signal);
gtk_signal_handler_unblock (GTK_OBJECT (sheet->entry),
sheet->insert_signal);
changed = TRUE;
}
if (new_position != cursor_position)
{
gtk_editable_set_position (editable, new_position);
changed = TRUE;
}
if ((new_start != start_sel) || (new_end != end_sel))
{
gtk_entry_select_region(GTK_ENTRY(sheet->entry),
new_start, new_end);
changed = TRUE;
}
if (changed)
item_edit_redraw(ITEM_EDIT(sheet->item_editor));
return result;
}
static gint
gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
{
@ -1441,6 +1649,9 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
table = sheet->table;
header = table->handlers[0][0];
if (gnucash_sheet_direct_event(sheet, (GdkEvent *) event))
return TRUE;
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
&current_p_row, &current_p_col);
@ -1485,7 +1696,7 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
break;
case GDK_KP_Down:
case GDK_Down:
if (event->state & GDK_CONTROL_MASK)
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
{
ItemEdit *item_edit;
@ -1830,6 +2041,8 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
gint virt_col, gint cell_row, gint cell_col)
{
SheetBlock *block;
SheetBlockStyle *style;
Table *table;
gint p_row, p_col;
gchar *text;
@ -1840,9 +2053,14 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
table = sheet->table;
block = gnucash_sheet_get_block (sheet, virt_row, virt_col);
style = block->style;
if (!style)
return;
if (cell_row >= 0 && cell_row <= block->style->nrows
&& cell_col >= 0 && cell_col <= block->style->ncols) {
if (cell_row >= 0 && cell_row <= style->nrows
&& cell_col >= 0 && cell_col <= style->ncols) {
if (block->entries[cell_row][cell_col])
g_free (block->entries[cell_row][cell_col]);
@ -1859,6 +2077,55 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
}
gint
gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
{
int virt_row;
int cell_row;
int max = 0;
int width;
SheetBlock *block;
SheetBlockStyle *style;
GdkFont *font;
g_return_val_if_fail (virt_col >= 0, 0);
g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
g_return_val_if_fail (cell_col >= 0, 0);
for (virt_row = 1; virt_row < sheet->num_virt_rows ; virt_row++) {
block = gnucash_sheet_get_block (sheet, virt_row, virt_col);
style = block->style;
if (!style)
continue;
if (cell_col < style->ncols)
for (cell_row = 0; cell_row < style->nrows; cell_row++) {
const char *text = gnucash_sheet_block_get_text (sheet,
virt_row, virt_col,
cell_row, cell_col);
if (style->fonts[cell_row][cell_col])
font = style->fonts[cell_row][cell_col];
else
font = GNUCASH_GRID(sheet->grid)->normal_font;
if (!text || strlen(text) == 0) {
text = style->labels[cell_row][cell_col];
font = style->header_font;
}
width = gdk_string_measure (font, text) + 2*CELL_HPADDING;
max = MAX (max, width);
}
}
return max;
}
static void
gnucash_sheet_block_destroy (GnucashSheet *sheet, gint virt_row, gint virt_col)
{
@ -1954,7 +2221,7 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
Table *table;
gint num_virt_rows;
gint i, j;
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUCASH_IS_SHEET(sheet));
g_return_if_fail (sheet->table != NULL);
@ -1968,7 +2235,7 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
gnucash_sheet_resize (sheet);
/* fill it up */
for ( i = 0; i < table->num_virt_rows; i++)
for (i = 0; i < table->num_virt_rows; i++)
for (j = 0; j < table->num_virt_cols; j++)
gnucash_sheet_block_set_from_table (sheet, i, j);
@ -1982,6 +2249,53 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
}
static gboolean
gnucash_sheet_selection_clear (GtkWidget *widget,
GdkEventSelection *event)
{
GnucashSheet *sheet;
g_return_val_if_fail(widget != NULL, FALSE);
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), FALSE);
sheet = GNUCASH_SHEET(widget);
return item_edit_selection_clear(ITEM_EDIT(sheet->item_editor), event);
}
static void
gnucash_sheet_selection_get (GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GnucashSheet *sheet;
g_return_if_fail(widget != NULL);
g_return_if_fail(GNUCASH_IS_SHEET(widget));
sheet = GNUCASH_SHEET(widget);
item_edit_selection_get(ITEM_EDIT(sheet->item_editor),
selection_data, info, time);
}
static void
gnucash_sheet_selection_received (GtkWidget *widget,
GtkSelectionData *selection_data,
guint time)
{
GnucashSheet *sheet;
g_return_if_fail(widget != NULL);
g_return_if_fail(GNUCASH_IS_SHEET(widget));
sheet = GNUCASH_SHEET(widget);
item_edit_selection_received(ITEM_EDIT(sheet->item_editor),
selection_data, time);
}
static void
gnucash_sheet_class_init (GnucashSheetClass *class)
{
@ -1999,12 +2313,18 @@ gnucash_sheet_class_init (GnucashSheetClass *class)
object_class->destroy = gnucash_sheet_destroy;
widget_class->realize = gnucash_sheet_realize;
widget_class->size_request = gnucash_sheet_size_request;
widget_class->size_allocate = gnucash_sheet_size_allocate;
widget_class->key_press_event = gnucash_sheet_key_press_event;
widget_class->button_press_event = gnucash_button_press_event;
widget_class->button_release_event = gnucash_button_release_event;
widget_class->motion_notify_event = gnucash_motion_event;
widget_class->selection_clear_event = gnucash_sheet_selection_clear;
widget_class->selection_received = gnucash_sheet_selection_received;
widget_class->selection_get = gnucash_sheet_selection_get;
}
@ -2052,7 +2372,9 @@ gnucash_sheet_init (GnucashSheet *sheet)
sheet->num_virt_cols = 0;
sheet->item_editor = NULL;
sheet->entry = NULL;
sheet->editing = FALSE;
sheet->editing = FALSE;
sheet->button = 0;
sheet->grabbed = FALSE;
sheet->default_width = -1;
sheet->default_height = -1;
sheet->width = 0;
@ -2098,7 +2420,7 @@ gnucash_sheet_new (Table *table)
GnomeCanvasGroup *sheet_group;
g_return_val_if_fail (table != NULL, NULL);
sheet = gnucash_sheet_create (table);
/* FIXME: */
@ -2119,7 +2441,6 @@ gnucash_sheet_new (Table *table)
/* some register data */
sheet->layout_info_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
sheet->dimensions_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
/* The cursor */
sheet->cursor = gnucash_cursor_new (sheet_group);
@ -2237,10 +2558,8 @@ gnucash_register_attach_popup(GnucashRegister *reg, GtkWidget *popup,
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
g_return_if_fail(GTK_IS_WIDGET(popup));
g_return_if_fail(reg->sheet != NULL);
g_return_if_fail(reg->header_canvas != NULL);
gnome_popup_menu_attach(popup, reg->sheet, data);
gnome_popup_menu_attach(popup, reg->header_canvas, data);
}
@ -2297,7 +2616,6 @@ gnucash_register_new (Table *table)
reg->hscrollbar = scrollbar;
gtk_widget_show(scrollbar);
return widget;
}

View File

@ -170,6 +170,9 @@ typedef struct {
gint editing;
gint button; /* mouse button being held down */
gboolean grabbed; /* has the grab */
guint insert_signal;
guint delete_signal;
guint changed_signal;
@ -206,6 +209,8 @@ void gnucash_sheet_set_top_block (GnucashSheet *sheet, int new_top_block,
SheetBlock *gnucash_sheet_get_block (GnucashSheet *sheet, gint vrow,
gint vcol);
gint
gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col);
gint gnucash_sheet_col_get_distance(GnucashSheet *sheet, int v_row, int col_a, int col_b);
@ -253,6 +258,12 @@ void gnucash_register_goto_next_virt_row (GnucashRegister *reg);
void gnucash_register_attach_popup(GnucashRegister *reg, GtkWidget *popup,
gpointer data);
void gnucash_register_set_initial_rows(guint num_rows);
void gnucash_register_cut_clipboard (GnucashRegister *reg);
void gnucash_register_copy_clipboard (GnucashRegister *reg);
void gnucash_register_paste_clipboard (GnucashRegister *reg);
typedef struct {
GnomeCanvasClass parent_class;

View File

@ -277,14 +277,14 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
case GNUCASH_CURSOR_SPLIT:
{
int i, j;
double perc[1][8] = {{0.10, 0.07, 0.15, 0.30, 0.02, 0.12, 0.12, 0.12}};
double perc[1][8] = {{0.10, 0.07, 0.25, 0.20, 0.02, 0.12, 0.12, 0.12}};
CellLayoutData ld[1][8] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 10 ,0,0,0,0,0, 0, 0, XFRM_STR},
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0, 10 ,0,0,0,0,0, 0, 0, XFRM_STR},
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
}};
@ -307,21 +307,21 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
case GNUCASH_CURSOR_DOUBLE:
{
int i, j;
double perc[2][8] = {{0.10, 0.07, 0.15, 0.30, 0.02, 0.12, 0.12, 0.12},
{0.10, 0.07, 0.15, 0.68, 0.0, 0.0, 0.0, 0.0}};
double perc[2][8] = {{0.10, 0.07, 0.25, 0.20, 0.02, 0.12, 0.12, 0.12},
{0.10, 0.07, 0.83, 0.0, 0.0, 0.0, 0.0, 0.0}};
CellLayoutData ld[2][8] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0,0 ,0,0,0,0,0, 0, 0, XFRM_STR},
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0,0 ,0,0,0,0,0, 0, 0, XFRM_STR},
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL}},
{{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,1,0,1, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,2, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,0,7, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,7, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
@ -359,14 +359,14 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
case GNUCASH_CURSOR_SPLIT:
{
int i, j;
double perc[1][11] = {{0.09, 0.06, 0.11, 0.23, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09}};
double perc[1][11] = {{0.09, 0.06, 0.20, 0.14, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09}};
CellLayoutData ld[1][11] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
@ -394,15 +394,15 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
case GNUCASH_CURSOR_DOUBLE:
{
int i, j;
double perc[2][11] = {{0.09, 0.06, 0.11, 0.23, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09},
double perc[2][11] = {{0.09, 0.06, 0.20, 0.14, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09},
{0.0, 0.15, 0.11, 0.74, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
CellLayoutData ld[2][11] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
{CHARS_MIN, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
@ -410,8 +410,8 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL}},
{{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,1,0,1, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,2, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,0,10, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,10, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
@ -537,7 +537,7 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellLayoutInfo *layout_info,
g_return_if_fail (font != NULL);
for (j = 0; j < layout_info->ncols; j++) {
dimensions->pixel_widths[i][j] = layout_info->cell_perc[i][j] * dimensions->width + 0.5;
dimensions->pixel_widths[i][j] = layout_info->cell_perc[i][j] * dimensions->width + 0.5;
dimensions->pixel_heights[i][j] =
font->ascent + font->descent +
2*CELL_VPADDING;
@ -724,7 +724,7 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
if (layout_info->flags[i][j] & PIXELS_MIN) {
int allowed = dimensions->pixel_widths[i][j]
- layout_info->pixels_min[i][j];
adjustments[j] = MIN (allowed, cellspace);
adjustments[j] = MAX(0, MIN (allowed, cellspace));
done[j] = (allowed < cellspace);
}
else adjustments[j] = cellspace;
@ -733,8 +733,8 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
else {
if (layout_info->flags[i][j] & PIXELS_MAX) {
int allowed = dimensions->pixel_widths[i][j]
- layout_info->pixels_min[i][j];
adjustments[j] = MAX (allowed, cellspace);
- layout_info->pixels_max[i][j];
adjustments[j] = MIN(0, MAX (allowed, cellspace));
done[j] = (allowed >cellspace);
}
else adjustments[j] = cellspace;
@ -772,7 +772,7 @@ set_dimensions_pass_four(GnucashSheet *sheet, CellLayoutInfo *layout_info,
int i = row, j;
int c1, c2;
int r;
for (j = 0; j < layout_info->ncols; j++) {
if (!(layout_info->flags[i][j] & (LEFT_ALIGNED | RIGHT_ALIGNED | PIXELS_FIXED))) {
@ -797,16 +797,52 @@ gnucash_style_default_width(GnucashSheet *sheet, SheetBlockStyle *style)
{
CellLayoutInfo *layout_info;
CellDimensions *dimensions;
gint width;
gint i;
layout_info = style->layout_info;
dimensions = style->dimensions;
set_dimensions_pass_one(sheet, layout_info, dimensions, 0);
set_dimensions_pass_two(sheet, layout_info, dimensions, 0);
dimensions->height = 0;
width = dimensions->width = 0;
return compute_row_width(dimensions, 0, 0, layout_info->ncols);
/* Well, this is kind of wierd, isn't it. We do this five times
* because pass one and pass two interact in a strange way. Pass
* one sets widths based on percentages, and then pass two fixes
* them up based on layout info. If we only do this once, then
* when we get the allocation and we recompute them below, the
* pass one iteration messes up the pass two fixes. Then, when
* pass two is run again, the size gets bumped up to compensate.
* Running these 5 times is a hack to make the window come up
* in full horizontal view. */
for (i = 0; i < 5; i++)
{
set_dimensions_pass_one(sheet, layout_info, dimensions, 0);
set_dimensions_pass_two(sheet, layout_info, dimensions, 0);
width = compute_row_width(dimensions, 0, 0,
layout_info->ncols - 1);
dimensions->width = width;
}
return width;
}
gint
gnucash_style_row_width(SheetBlockStyle *style, int row)
{
CellLayoutInfo *layout_info;
CellDimensions *dimensions;
layout_info = style->layout_info;
dimensions = style->dimensions;
return compute_row_width(dimensions, row, 0, layout_info->ncols - 1);
}
static void
compute_cell_origins_x (CellDimensions *dimensions, int row)
{
@ -894,7 +930,8 @@ gnucash_sheet_style_set_dimensions (GnucashSheet *sheet,
g_return_if_fail (GNUCASH_IS_SHEET (sheet));
g_return_if_fail (style != NULL);
style_recompute_layout_dimensions (sheet, style->layout_info, style->dimensions);
style_recompute_layout_dimensions (sheet, style->layout_info,
style->dimensions);
}
gint
@ -907,8 +944,8 @@ gnucash_style_col_is_resizable (SheetBlockStyle *style, int col)
}
/*
* Set width of a specified cell and set the PIXEL_FIXED flag. If
* same_size is TRUE, also set the width of any
* Set width of a specified cell and set the PIXEL_FIXED flag.
* If same_size is TRUE, also set the width of any
* SAME_SIZE cell which references this one. Otherwise those
* cells are set to PIXELS_FIXED with their current width.
*/
@ -925,18 +962,12 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
if (width >= 0) {
#if 0
if (style->dimensions->pixel_widths[0][col] > width) {
style->layout_info->pixels_max[0][col] = width;
style->layout_info->flags[0][col] = PIXELS_MAX;
}
else {
style->layout_info->pixels_min[0][col] = width;
style->layout_info->flags[0][col] = PIXELS_MIN;
}
#endif
style->layout_info->flags[0][col] = PIXELS_FIXED;
style->layout_info->pixels_width[0][col] = width;
/* Note that we may want to preserve the FILL flag on
* this, but for now let's leave it off.
* style->layout_info->flags[0][col] = PIXELS_FIXED |
* (style->layout_info->flags[0][col] & FILL); */
style->layout_info->flags[0][col] = PIXELS_FIXED;
style->dimensions->pixel_widths[0][col] = width;
for (i = 0; i < style->nrows; i++) {
@ -947,7 +978,12 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
if (same_size)
style->dimensions->pixel_widths[i][j] = width;
else
{
style->layout_info->flags[i][j] = PIXELS_FIXED;
style->layout_info->pixels_width[i][j] =
style->dimensions->pixel_widths[i][j];
}
}
}
}
@ -961,8 +997,6 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
}
void
gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
{
@ -991,14 +1025,16 @@ gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
style->layout_info->refcount--;
if (style->layout_info->refcount == 0) {
g_hash_table_remove (sheet->layout_info_hash_table, style_get_key (style));
g_hash_table_remove (sheet->layout_info_hash_table,
style_get_key (style));
style_layout_info_destroy (style->layout_info);
}
style->dimensions->refcount--;
if (style->dimensions->refcount == 0) {
g_hash_table_remove (sheet->dimensions_hash_table, style_get_key (style));
g_hash_table_remove (sheet->dimensions_hash_table,
style_get_key (style));
style_dimensions_destroy (style->dimensions);
}
@ -1006,13 +1042,71 @@ gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
}
/* Recompiles the style information from the cellblock, without
* recomputing the layout info or the dimensions. WARNING: this
* function assumes that the space for the style info has been
* allocated already. */
void
gnucash_sheet_style_recompile(SheetBlockStyle *style, CellBlock *cellblock,
SplitRegister *sr, gint cursor_type)
{
gint i, j, type;
char *label;
for (i = 0; i < style->nrows; i++)
for (j = 0; j < style->ncols; j++) {
type = cellblock->cell_types[i][j];
style->widths[i][j] = cellblock->widths[j];
style->fonts[i][j] = NULL;
style->header_font = gnucash_default_font;
if (type > -1)
label = sr->header_label_cells[type]->value;
else if (cursor_type == GNUCASH_CURSOR_HEADER)
label = cellblock->cells[i][j]->value;
else
label = "";
g_free(style->labels[i][j]);
style->labels[i][j] = g_strdup(label);
style->active_bg_color[i][j] =
gnucash_color_argb_to_gdk
(cellblock->active_bg_color);
style->inactive_bg_color[i][j] =
gnucash_color_argb_to_gdk
(cellblock->passive_bg_color);
switch (cellblock->alignments[j]) {
case ALIGN_RIGHT:
style->alignments[i][j] =
GTK_JUSTIFY_RIGHT;
break;
case ALIGN_CENTER:
style->alignments[i][j] =
GTK_JUSTIFY_CENTER;
break;
default:
case ALIGN_FILL:
case ALIGN_LEFT:
style->alignments[i][j] =
GTK_JUSTIFY_LEFT;
break;
}
}
}
SheetBlockStyle *
gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
gint cursor_type)
{
gint i, j;
SheetBlockStyle *style;
SplitRegister *sr;
gint i;
g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (GNUCASH_IS_SHEET (sheet), NULL);
@ -1035,7 +1129,7 @@ gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
style->active_bg_color = g_new0 (GdkColor **, cellblock->numRows);
style->inactive_bg_color = g_new0 (GdkColor **, cellblock->numRows);
style->labels = g_new0 (char **, cellblock->numRows);
for ( i = 0; i < style->nrows; i++) {
style->widths[i] = g_new0(gint, style->ncols);
style->alignments[i] = g_new0 (GtkJustification, style->ncols);
@ -1045,42 +1139,7 @@ gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
style->labels[i] = g_new0 (char *, style->ncols);
}
for (i = 0; i < style->nrows; i++)
for (j = 0; j < style->ncols; j++) {
gint type = cellblock->cell_types[i][j];
char *label;
style->widths[i][j] = cellblock->widths[j];
style->fonts[i][j] = NULL;
style->header_font = gnucash_default_font;
if (type > -1)
label = sr->header_label_cells[type]->value;
else if (cursor_type == GNUCASH_CURSOR_HEADER)
label = cellblock->cells[i][j]->value;
else
label = "";
style->labels[i][j] = g_strdup(label);
style->active_bg_color[i][j] = gnucash_color_argb_to_gdk (cellblock->active_bg_color);
style->inactive_bg_color[i][j] = gnucash_color_argb_to_gdk (cellblock->passive_bg_color);
switch (cellblock->alignments[j]) {
case ALIGN_RIGHT:
style->alignments[i][j] = GTK_JUSTIFY_RIGHT;
break;
case ALIGN_CENTER:
style->alignments[i][j] = GTK_JUSTIFY_CENTER;
break;
default:
case ALIGN_FILL:
case ALIGN_LEFT:
style->alignments[i][j] = GTK_JUSTIFY_LEFT;
break;
}
}
gnucash_sheet_style_recompile(style, cellblock, sr, cursor_type);
gnucash_style_layout_init (sheet, style);
gnucash_style_dimensions_init (sheet, style);

View File

@ -34,6 +34,8 @@ void gnucash_sheet_style_set_col_width (GnucashSheet *sheet,
gint gnucash_style_default_width(GnucashSheet *sheet, SheetBlockStyle *style);
gint gnucash_style_row_width(SheetBlockStyle *style, int row);
void gnucash_sheet_style_set_dimensions (GnucashSheet *sheet,
SheetBlockStyle *style);
@ -43,6 +45,11 @@ SheetBlockStyle * gnucash_sheet_style_compile (GnucashSheet *sheet,
CellBlock *cellblock,
gint cursor_type);
void gnucash_sheet_style_recompile (SheetBlockStyle *style,
CellBlock *cellblock,
SplitRegister *sr,
gint cursor_type);
SheetBlockStyle *gnucash_sheet_get_style (GnucashSheet *sheet, gint vrow,
gint vcol);

View File

@ -0,0 +1,101 @@
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
\********************************************************************/
/* quickfillcell-gnome.c
*
* Implements gnome dependant quickfill cell functions.
*/
#include "config.h"
#include <gnome.h>
#include "quickfillcell.h"
#include "util.h"
static gncBoolean
QuickFillDirect (BasicCell *bcell,
const char *oldval,
char **newval_ptr,
int *cursor_position,
int *start_selection,
int *end_selection,
void *gui_data)
{
QuickFillCell *cell = (QuickFillCell *) bcell;
GdkEventKey *event = gui_data;
QuickFill *match;
int prefix_len;
if (event->type != GDK_KEY_PRESS)
return GNC_F;
switch (event->keyval) {
case GDK_slash:
if (!(event->state & GDK_MOD1_MASK))
return GNC_F;
break;
case GDK_Tab:
case GDK_ISO_Left_Tab:
if (!(event->state & GDK_CONTROL_MASK))
return GNC_F;
break;
default:
return GNC_F;
}
match = xaccGetQuickFillStrLen(cell->qfRoot, oldval, *cursor_position);
if (match == NULL)
return GNC_T;
match = xaccGetQuickFillUniqueLen(match, &prefix_len);
if (match == NULL)
return GNC_T;
if ((match->text != NULL) &&
(strncmp(match->text, oldval, strlen(oldval)) == 0) &&
(strcmp(match->text, oldval) != 0))
{
*newval_ptr = strdup(match->text);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);
}
*cursor_position += prefix_len;
*start_selection = *cursor_position;
*end_selection = -1;
return GNC_T;
}
void
xaccQuickFillGUIInit (QuickFillCell *cell)
{
if (cell == NULL)
return;
cell->cell.direct_update = QuickFillDirect;
}
/* =============== end of file =================== */
/*
Local Variables:
c-basic-offset: 8
End:
*/

View File

@ -38,7 +38,7 @@
static void PriceSetValue (BasicCell *, const char *);
static char * xaccPriceCellPrintValue (PriceCell *cell);
/* set the color of the text to red, if teh value is negative */
/* set the color of the text to red, if the value is negative */
/* hack alert -- the actual color should probably be configurable */
#define COLORIZE(cell,amt) { \
if (0.0 > amt) { \
@ -79,7 +79,7 @@ PriceEnter (BasicCell *_cell,
static const char *
PriceMV (BasicCell *_cell,
const char * oldval,
const char *oldval,
const char *change,
const char *newval,
int *cursor_position,
@ -96,21 +96,28 @@ PriceMV (BasicCell *_cell,
decimal_point = lc->decimal_point[0];
/* accept the newval string if user action was delete, etc. */
if (change) {
/* if change is a decimal point, then count decimal points */
if (decimal_point == change[0]) {
int i, count=0;
for (i=0; 0 != newval[i]; i++) {
if (decimal_point == newval[i]) count ++;
}
if (1 < count) return NULL;
} else {
/* accept numeric, reject non-alpha edits */
if (! (isdigit (change[0]))) return NULL;
if (change != NULL)
{
int i, count=0;
for (i=0; 0 != change[i]; i++)
{
/* accept only numbers or a decimal point */
if (!isdigit(change[i]) && (decimal_point != change[i]))
return NULL;
if (decimal_point == change[i])
count++;
}
for (i=0; 0 != oldval[i]; i++)
if (decimal_point == oldval[i])
count++;
if (1 < count) return NULL;
}
/* parse the float pt value and store it */
/* parse the float pt value and store it */
cell->amount = xaccParseAmount (newval, cell->monetary);
SET ((&(cell->cell)), newval);
return newval;
@ -131,11 +138,34 @@ PriceLeave (BasicCell *_cell, const char *val)
return val;
/* Otherwise, return the new one. */
SET ((&(cell->cell)), newval);
return strdup(newval);
}
/* ================================================ */
static char *
PriceHelp(BasicCell *bcell)
{
PriceCell *cell = (PriceCell *) bcell;
if ((bcell->value != NULL) && (bcell->value[0] != 0))
{
char *help_str;
help_str = xaccPriceCellPrintValue(cell);
return strdup(help_str);
}
if (bcell->blank_help != NULL)
return strdup(bcell->blank_help);
return NULL;
}
/* ================================================ */
PriceCell *
xaccMallocPriceCell (void)
{
@ -153,8 +183,9 @@ xaccInitPriceCell (PriceCell *cell)
xaccInitBasicCell( &(cell->cell));
cell->amount = 0.0;
cell->blank_zero = 1;
cell->prt_format = strdup ("%m");
cell->precision = 2;
cell->blank_zero = GNC_T;
cell->min_trail_zeros = 2;
cell->monetary = GNC_T;
SET ( &(cell->cell), "");
@ -164,6 +195,7 @@ xaccInitPriceCell (PriceCell *cell)
cell->cell.modify_verify = PriceMV;
cell->cell.leave_cell = PriceLeave;
cell->cell.set_value = PriceSetValue;
cell->cell.get_help_value = PriceHelp;
}
/* ================================================ */
@ -172,7 +204,6 @@ void
xaccDestroyPriceCell (PriceCell *cell)
{
cell->amount = 0.0;
free (cell->prt_format); cell->prt_format = 0x0;
xaccDestroyBasicCell ( &(cell->cell));
}
@ -182,34 +213,26 @@ static char *
xaccPriceCellPrintValue (PriceCell *cell)
{
static char buff[PRTBUF];
char tmpfmt[PRTBUF];
char tmpval[PRTBUF];
char *monet;
if (cell->blank_zero && DEQ(cell->amount, 0.0)) {
strcpy(buff, "");
return buff;
}
/* check for monetary-style format not natively supported by printf */
/* hack alert -- this type of extended function should be abstracted
* out to a gnc_sprintf type function, however, this is much
* easier said than done */
monet = strstr (cell->prt_format, "%m");
if (monet) {
strcpy (tmpfmt, cell->prt_format);
monet = strstr (tmpfmt, "%m");
*(monet+1) = 's';
xaccSPrintAmount (tmpval, cell->amount, PRTSEP);
snprintf (buff, PRTBUF, tmpfmt, tmpval);
} else {
snprintf (buff, PRTBUF, cell->prt_format, cell->amount);
}
xaccSPrintAmountGeneral(buff, cell->amount, PRTSEP, cell->precision,
cell->monetary, cell->min_trail_zeros);
return buff;
}
/* ================================================ */
double
xaccGetPriceCellValue (PriceCell *cell)
{
assert(cell != NULL);
return cell->amount;
}
void xaccSetPriceCellValue (PriceCell * cell, double amt)
{
@ -226,13 +249,12 @@ void xaccSetPriceCellValue (PriceCell * cell, double amt)
/* ================================================ */
void xaccSetPriceCellFormat (PriceCell * cell, char * fmt)
void
xaccSetPriceCellPrecision (PriceCell *cell, int precision)
{
if (cell->prt_format) free (cell->prt_format);
cell->prt_format = strdup (fmt);
assert(cell != NULL);
/* make sure that the cell is updated with the new format */
xaccSetPriceCellValue (cell, cell->amount);
cell->precision = precision;
}
/* ================================================ */
@ -240,11 +262,33 @@ void xaccSetPriceCellFormat (PriceCell * cell, char * fmt)
void
xaccSetPriceCellMonetary (PriceCell * cell, gncBoolean monetary)
{
assert(cell != NULL);
cell->monetary = monetary;
}
/* ================================================ */
void
xaccSetPriceCellMinTrailZeros (PriceCell * cell, int min_trail_zeros)
{
assert(cell != NULL);
cell->min_trail_zeros = min_trail_zeros;
}
/* ================================================ */
void
xaccSetPriceCellBlankZero (PriceCell *cell, gncBoolean blank_zero)
{
assert(cell != NULL);
cell->blank_zero = blank_zero;
}
/* ================================================ */
void xaccSetDebCredCellValue (PriceCell * deb,
PriceCell * cred, double amt)
{

View File

@ -53,12 +53,17 @@
#include "basiccell.h"
#include "gnc-common.h"
typedef struct _PriceCell {
typedef struct _PriceCell
{
BasicCell cell;
double amount; /* the amount associated with this cell */
short blank_zero; /* controls printing of zero values */
char *prt_format; /* controls display of value; printf format */
gncBoolean monetary; /* controls parsing of values */
double amount; /* the amount associated with this cell */
int precision; /* precision of printed values */
int min_trail_zeros; /* minimum number of trailing zeros to print */
gncBoolean blank_zero; /* controls printing of zero values */
gncBoolean monetary; /* controls parsing of values */
} PriceCell;
/* installs a callback to handle price recording */
@ -66,17 +71,22 @@ PriceCell * xaccMallocPriceCell (void);
void xaccInitPriceCell (PriceCell *);
void xaccDestroyPriceCell (PriceCell *);
/* updates amount, string format is three decimal places */
void xaccSetPriceCellValue (PriceCell *, double amount);
/* return the value of a price cell */
double xaccGetPriceCellValue (PriceCell *cell);
/* The xaccSetPriceCellFormat() method is used to control how
* the cell contents are displayed. It accepts as an argument
* a printf-style format. The format must control the display
* of a double-precision float. See the printf() command for
* allowed syntax. The default format is "%m" for a monetary
* style format.
*/
void xaccSetPriceCellFormat (PriceCell *, char * fmt);
/* updates amount, string format is three decimal places */
void xaccSetPriceCellValue (PriceCell *cell, double amount);
/* sets the precision of the printed value. Defaults to 2 */
void xaccSetPriceCellPrecision (PriceCell *cell, int precision);
/* Sets the mininum number of trailing decimal zeros that must
* be printed. Defaults to 2. */
void xaccSetPriceCellMinTrailZeros (PriceCell *cell, int);
/* determines whether 0 values are left blank or printed.
* defaults to true. */
void xaccSetPriceCellBlankZero (PriceCell *cell, gncBoolean);
/* The xaccSetPriceCellMonetary() sets a flag which determines
* how string amounts are parsed, either as monetary or
@ -88,7 +98,7 @@ void xaccSetPriceCellMonetary (PriceCell *, gncBoolean);
* the credit cell if amount is positive, and makes the other cell
* blank. */
void xaccSetDebCredCellValue (PriceCell *deb,
PriceCell *cred, double amount);
PriceCell *cred, double amount);
#endif /* __XACC_PRICE_CELL_C__ */

View File

@ -0,0 +1,29 @@
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
\********************************************************************/
/* quickfillcell-motif.c
*
* Implements motif dependent quick fill cell functions.
*/
#include "quickfillcell.h"
void
xaccQuickFillGUIInit (QuickFillCell *cell)
{
/* does nothing */
}

View File

@ -257,6 +257,8 @@ xaccInitQuickFillCell (QuickFillCell *cell)
cell->cell.modify_verify = quick_modify;
cell->cell.leave_cell = quick_leave;
cell->cell.set_value = quick_set;
xaccQuickFillGUIInit (cell);
}
/* ================================================ */

View File

@ -61,6 +61,9 @@ void xaccDestroyQuickFillCell (QuickFillCell *);
void xaccSetQuickFillCellValue (QuickFillCell *, const char *);
void xaccSetQuickFillSort (QuickFillCell *, QuickFillSort);
/* GUI-dependent */
void xaccQuickFillGUIInit (QuickFillCell *);
#endif /* __XACC_FILL_CELL_C__ */
/* --------------- end of file ---------------------- */

View File

@ -43,6 +43,27 @@
/* This static indicates the debugging module that this .o belongs to. */
static short module = MOD_REGISTER;
static SplitRegisterColors reg_colors = {
0xffdddd, /* pale red, single cursor active */
0xccccff, /* pale blue, single cursor passive */
0xccccff, /* pale blue, single cursor passive 2 */
0xffdddd, /* pale red, double cursor active */
0xccccff, /* pale blue, double cursor passive */
0xffffff, /* white, double cursor passive 2 */
GNC_F, /* double mode alternate by physical row */
0xffdddd, /* pale red, trans cursor active */
0xccccff, /* pale blue, trans cursor passive */
0xffffdd, /* pale yellow, split cursor active */
0xffffff, /* white, split cursor passive */
0xffffff /* white, header color */
};
/* utility defines for cell configuration data */
#define DATE_CELL 0
#define NUM_CELL 1
@ -89,9 +110,9 @@ static short module = MOD_REGISTER;
#define DATE_CELL_ALIGN ALIGN_RIGHT
#define NUM_CELL_ALIGN ALIGN_LEFT
#define ACTN_CELL_ALIGN ALIGN_LEFT
#define XFRM_CELL_ALIGN ALIGN_LEFT
#define MXFRM_CELL_ALIGN ALIGN_LEFT
#define XTO_CELL_ALIGN ALIGN_LEFT
#define XFRM_CELL_ALIGN ALIGN_RIGHT
#define MXFRM_CELL_ALIGN ALIGN_RIGHT
#define XTO_CELL_ALIGN ALIGN_RIGHT
#define DESC_CELL_ALIGN ALIGN_LEFT
#define MEMO_CELL_ALIGN ALIGN_LEFT
#define RECN_CELL_ALIGN ALIGN_CENTER
@ -104,14 +125,7 @@ static short module = MOD_REGISTER;
#define SHRS_CELL_ALIGN ALIGN_RIGHT
#define BALN_CELL_ALIGN ALIGN_RIGHT
/* Use 4 decimal places for everything that isn't a $ value
* Perhaps this should be changed to store precision selection
* in a config file. */
#define SHRS_CELL_FORMAT "%0.4f"
#define DEBIT_CELL_FORMAT "%0.4f"
#define CREDIT_CELL_FORMAT "%0.4f"
#define PRICE_CELL_FORMAT "%0.4f"
#define SHARES_PRECISION 4
/* ============================================== */
@ -357,27 +371,29 @@ configLayout (SplitRegister *reg)
curs = reg->double_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
FANCY (BALN, balance, 7, 0);
FANCY (ACTN, action, 1, 1);
FANCY (MXFRM, mxfrm, 2, 1);
BASIC (MEMO, memo, 3, 1);
FANCY (MEMO, memo, 2, 1);
curs = reg->trans_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
FANCY (BALN, balance, 7, 0);
curs = reg->split_cursor;
FANCY (ACTN, action, 1, 0);
FANCY (XFRM, xfrm, 2, 0);
BASIC (MEMO, memo, 3, 0);
FANCY (MEMO, memo, 2, 0);
FANCY (XFRM, xfrm, 3, 0);
FANCY (NDEBT, ndebit, 5, 0);
FANCY (NCRED, ncredit, 6, 0);
@ -385,8 +401,8 @@ configLayout (SplitRegister *reg)
curs = reg->single_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (MXFRM, mxfrm, 2, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
@ -404,7 +420,8 @@ configLayout (SplitRegister *reg)
curs = reg->double_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
@ -414,14 +431,13 @@ configLayout (SplitRegister *reg)
FANCY (BALN, balance, 10, 0);
FANCY (ACTN, action, 1, 1);
FANCY (MXFRM, mxfrm, 2, 1);
BASIC (MEMO, memo, 3, 1);
FANCY (MEMO, memo, 2, 1);
/* only the transaction cursor gets used */
curs = reg->trans_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
@ -432,8 +448,8 @@ configLayout (SplitRegister *reg)
curs = reg->split_cursor;
FANCY (ACTN, action, 1, 0);
FANCY (XFRM, xfrm, 2, 0);
BASIC (MEMO, memo, 3, 0);
FANCY (MEMO, memo, 2, 0);
FANCY (XFRM, xfrm, 3, 0);
FANCY (NDEBT, ndebit, 5, 0);
FANCY (NCRED, ncredit, 6, 0);
@ -441,8 +457,8 @@ configLayout (SplitRegister *reg)
curs = reg->single_cursor;
FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0);
FANCY (MXFRM, mxfrm, 2, 0);
FANCY (DESC, desc, 3, 0);
FANCY (DESC, desc, 2, 0);
FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
@ -700,7 +716,8 @@ configTraverse (SplitRegister *reg)
/* ============================================== */
SplitRegister * xaccMallocSplitRegister (int type)
SplitRegister *
xaccMallocSplitRegister (int type)
{
SplitRegister * reg;
reg = (SplitRegister *) malloc (sizeof (SplitRegister));
@ -710,39 +727,83 @@ SplitRegister * xaccMallocSplitRegister (int type)
/* ============================================== */
void
xaccSetSplitRegisterColors (SplitRegisterColors reg_colors_new)
{
reg_colors = reg_colors_new;
}
/* ============================================== */
static void
configTable(SplitRegister *reg)
{
int style = reg->type & REG_STYLE_MASK;
if ((reg == NULL) || (reg->table == NULL))
return;
switch (style) {
case REG_SINGLE_LINE:
case REG_SINGLE_DYNAMIC:
reg->table->alternate_bg_colors = GNC_T;
break;
case REG_DOUBLE_LINE:
case REG_DOUBLE_DYNAMIC:
reg->table->alternate_bg_colors = reg_colors.double_alternate_virt;
break;
default:
reg->table->alternate_bg_colors = GNC_F;
break;
}
}
/* ============================================== */
void
xaccSplitRegisterConfigColors (SplitRegister *reg)
{
reg->single_cursor->active_bg_color =
reg_colors.single_cursor_active_bg_color;
reg->single_cursor->passive_bg_color =
reg_colors.single_cursor_passive_bg_color;
reg->single_cursor->passive_bg_color2 =
reg_colors.single_cursor_passive_bg_color2;
reg->double_cursor->active_bg_color =
reg_colors.double_cursor_active_bg_color;
reg->double_cursor->passive_bg_color =
reg_colors.double_cursor_passive_bg_color;
reg->double_cursor->passive_bg_color2 =
reg_colors.double_cursor_passive_bg_color2;
reg->trans_cursor->active_bg_color =
reg_colors.trans_cursor_active_bg_color;
reg->trans_cursor->passive_bg_color =
reg_colors.trans_cursor_passive_bg_color;
reg->trans_cursor->passive_bg_color2 =
reg_colors.trans_cursor_passive_bg_color;
reg->split_cursor->active_bg_color =
reg_colors.split_cursor_active_bg_color;
reg->split_cursor->passive_bg_color =
reg_colors.split_cursor_passive_bg_color;
reg->split_cursor->passive_bg_color2 =
reg_colors.split_cursor_passive_bg_color;
reg->header->active_bg_color = reg_colors.header_bg_color;
reg->header->passive_bg_color = reg_colors.header_bg_color;
reg->header->passive_bg_color2 = reg_colors.header_bg_color;
configTable(reg);
}
/* ============================================== */
static void
configCursors (SplitRegister *reg)
{
/* --------------------------- */
/* set the color of the cells in the cursors */
/* hack alert -- the actual color should depend on the
* type of register. */
/* they used to be the following, once upon a time:
"*regbank.oddRowBackground: #aaccff",
"*regcash.oddRowBackground: #ccffcc",
"*regasset.oddRowBackground: #aaffcc",
"*regcredit.oddRowBackground: #ffffaa",
"*regliability.oddRowBackground: #ffcccc",
"*ledportfolio.oddRowBackground: #ccffff",
"*regmutual.oddRowBackground: #ccffff",
"*regincome.oddRowBackground: #aaccff",
"*regexpense.oddRowBackground: #ffcccc",
"*regequity.oddRowBackground: #ffffaa",
"*ledgportfolio.evenRowBackground:grey",
"*regmutual.evenRowBackground: grey",
*/
reg->single_cursor->active_bg_color = 0xffdddd; /* pale red */
reg->single_cursor->passive_bg_color = 0xccccff; /* pale blue */
reg->double_cursor->active_bg_color = 0xffdddd; /* pale red */
reg->double_cursor->passive_bg_color = 0xccccff; /* pale blue */
reg->trans_cursor->active_bg_color = 0xffdddd; /* pale red */
reg->trans_cursor->passive_bg_color = 0xccccff; /* pale blue */
reg->split_cursor->active_bg_color = 0xffffdd; /* pale yellow */
reg->split_cursor->passive_bg_color = 0xffffff; /* white */
xaccSplitRegisterConfigColors(reg);
}
/* ============================================== */
@ -808,6 +869,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
CellBlock *header;
int phys_r, phys_c;
reg->table = NULL;
reg->user_data = NULL;
reg->destroy = NULL;
reg->type = type;
@ -835,7 +897,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
HDR (VALU);
HDR (SHRS);
HDR (BALN);
HDR (NCRED);
HDR (NDEBT);
@ -854,7 +916,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
NEW (mxfrm, Combo);
NEW (xto, Combo);
NEW (action, Combo);
NEW (memo, Text);
NEW (memo, QuickFill);
NEW (credit, Price);
NEW (debit, Price);
NEW (price, Price);
@ -885,9 +947,24 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
* cells handles this for us.
*/
reg -> nullCell -> input_output = XACC_CELL_ALLOW_NONE;
reg->nullCell->input_output = XACC_CELL_ALLOW_NONE;
xaccSetBasicCellValue (reg->nullCell, "");
/* The num cell is the transaction number */
xaccSetBasicCellBlankHelp (reg->numCell, NUM_CELL_HELP);
/* the xfer cells */
xaccSetBasicCellBlankHelp (&reg->mxfrmCell->cell, XFER_CELL_HELP);
xaccSetBasicCellBlankHelp (&reg->xfrmCell->cell, XFER_CELL_HELP);
xaccComboCellSetIgnoreString (reg->mxfrmCell, SPLIT_STR);
xaccComboCellSetIgnoreHelp (reg->mxfrmCell, TOOLTIP_MULTI_SPLIT);
/* the memo cell */
xaccSetBasicCellBlankHelp (&reg->memoCell->cell, MEMO_CELL_HELP);
/* the desc cell */
xaccSetBasicCellBlankHelp (&reg->descCell->cell, DESC_CELL_HELP);
/* balance cell does not accept input; its display only. */
/* however, we *do* want it to shadow the true cell contents when
* the cursor is repositioned. Othewise, it will just display
@ -901,17 +978,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
*/
reg->recnCell->input_output |= XACC_CELL_ALLOW_EXACT_ONLY;
/* the debit/credit/value cells show blank if value is 0.00 */
reg->debitCell->blank_zero = 1;
reg->creditCell->blank_zero = 1;
reg->valueCell->blank_zero = 1;
reg->ndebitCell->blank_zero = 1;
reg->ncreditCell->blank_zero = 1;
/* ok, now make sure the initail value of 0.0 is blanked.
* if this is not done, then various oddball situations
* will show the non-blanked values.
*/
/* Initialize price cells */
xaccSetPriceCellValue (reg->debitCell, 0.0);
xaccSetPriceCellValue (reg->creditCell, 0.0);
xaccSetPriceCellValue (reg->valueCell, 0.0);
@ -920,27 +987,31 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
/* The format for share-related info is a printf-style
* format string for a double. */
xaccSetPriceCellFormat (reg->shrsCell, SHRS_CELL_FORMAT);
xaccSetPriceCellMonetary (reg->shrsCell, GNC_F);
xaccSetPriceCellMinTrailZeros (reg->shrsCell, 0);
xaccSetPriceCellPrecision (reg->shrsCell, SHARES_PRECISION);
/* The action cell should accept strings not in the list */
xaccComboCellSetStrict (reg->actionCell, GNC_F);
xaccSetBasicCellBlankHelp (&reg->actionCell->cell, ACTION_CELL_HELP);
/* number format for share quantities in stock ledgers */
switch (type & REG_TYPE_MASK) {
case STOCK_REGISTER:
case PORTFOLIO:
case CURRENCY_REGISTER:
xaccSetPriceCellFormat (reg->debitCell, DEBIT_CELL_FORMAT);
xaccSetPriceCellFormat (reg->creditCell, CREDIT_CELL_FORMAT);
xaccSetPriceCellFormat (reg->ndebitCell, DEBIT_CELL_FORMAT);
xaccSetPriceCellFormat (reg->ncreditCell, CREDIT_CELL_FORMAT);
xaccSetPriceCellFormat (reg->priceCell, DEBIT_CELL_FORMAT);
xaccSetPriceCellMonetary (reg->debitCell, GNC_F);
xaccSetPriceCellMonetary (reg->creditCell, GNC_F);
xaccSetPriceCellMonetary (reg->ndebitCell, GNC_F);
xaccSetPriceCellMonetary (reg->ncreditCell, GNC_F);
xaccSetPriceCellMonetary (reg->priceCell, GNC_F);
xaccSetPriceCellMinTrailZeros (reg->debitCell, 0);
xaccSetPriceCellMinTrailZeros (reg->creditCell, 0);
xaccSetPriceCellMinTrailZeros (reg->ndebitCell, 0);
xaccSetPriceCellMinTrailZeros (reg->ncreditCell, 0);
xaccSetPriceCellPrecision (reg->debitCell, SHARES_PRECISION);
xaccSetPriceCellPrecision (reg->creditCell, SHARES_PRECISION);
xaccSetPriceCellPrecision (reg->ndebitCell, SHARES_PRECISION);
xaccSetPriceCellPrecision (reg->ncreditCell, SHARES_PRECISION);
xaccSetPriceCellPrecision (reg->priceCell, SHARES_PRECISION);
xaccSetBasicCellBlankHelp (&reg->priceCell->cell, PRICE_CELL_HELP);
xaccSetBasicCellBlankHelp (&reg->valueCell->cell, VALUE_CELL_HELP);
break;
default:
break;
@ -958,6 +1029,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
/* -------------------------------- */
phys_r = header->numRows;
reg->cursor_phys_col = 0;
reg->cursor_phys_row = phys_r; /* cursor on first line past header */
reg->cursor_virt_row = 1;
@ -986,6 +1058,8 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
xaccMoveCursor (table, header->numRows, 0);
reg->table = table;
configTable(reg);
}
/* ============================================== */
@ -997,12 +1071,14 @@ xaccConfigSplitRegister (SplitRegister *reg, int newtype)
reg->type = newtype;
/* Make sure that any GU elemnts associated with this reconfig
/* Make sure that any GUI elements associated with this reconfig
* are properly initialized. */
xaccCreateCursor (reg->table, reg->single_cursor);
xaccCreateCursor (reg->table, reg->double_cursor);
xaccCreateCursor (reg->table, reg->trans_cursor);
xaccCreateCursor (reg->table, reg->split_cursor);
configTable(reg);
}
/* ============================================== */
@ -1042,7 +1118,7 @@ xaccDestroySplitRegister (SplitRegister *reg)
xaccDestroyComboCell (reg->xfrmCell);
xaccDestroyComboCell (reg->mxfrmCell);
xaccDestroyComboCell (reg->xtoCell);
xaccDestroyBasicCell (reg->memoCell);
xaccDestroyQuickFillCell (reg->memoCell);
xaccDestroyPriceCell (reg->creditCell);
xaccDestroyPriceCell (reg->debitCell);
xaccDestroyPriceCell (reg->priceCell);
@ -1093,7 +1169,7 @@ xaccSplitRegisterGetChangeFlag (SplitRegister *reg)
changed |= MOD_XFRM & reg->xfrmCell->cell.changed;
changed |= MOD_MXFRM & reg->mxfrmCell->cell.changed;
changed |= MOD_XTO & reg->xtoCell->cell.changed;
changed |= MOD_MEMO & reg->memoCell->changed;
changed |= MOD_MEMO & reg->memoCell->cell.changed;
changed |= MOD_AMNT & reg->creditCell->cell.changed;
changed |= MOD_AMNT & reg->debitCell->cell.changed;
changed |= MOD_PRIC & reg->priceCell->cell.changed;
@ -1119,7 +1195,7 @@ xaccSplitRegisterClearChangeFlag (SplitRegister *reg)
reg->xfrmCell->cell.changed = 0;
reg->mxfrmCell->cell.changed = 0;
reg->xtoCell->cell.changed = 0;
reg->memoCell->changed = 0;
reg->memoCell->cell.changed = 0;
reg->creditCell->cell.changed = 0;
reg->debitCell->cell.changed = 0;
reg->priceCell->cell.changed = 0;

View File

@ -143,7 +143,7 @@ struct _SplitRegister {
ComboCell * xfrmCell;
ComboCell * mxfrmCell;
ComboCell * xtoCell;
BasicCell * memoCell;
QuickFillCell * memoCell;
PriceCell * creditCell;
PriceCell * debitCell;
PriceCell * priceCell;
@ -177,14 +177,41 @@ struct _SplitRegister {
/* The destroy callback gives user's a chance
* to free up any associated user_hook data */
void (* destroy) (SplitRegister *);
};
typedef struct _SplitRegisterColors SplitRegisterColors;
struct _SplitRegisterColors
{
uint32 single_cursor_active_bg_color;
uint32 single_cursor_passive_bg_color;
uint32 single_cursor_passive_bg_color2;
uint32 double_cursor_active_bg_color;
uint32 double_cursor_passive_bg_color;
uint32 double_cursor_passive_bg_color2;
gncBoolean double_alternate_virt;
uint32 trans_cursor_active_bg_color;
uint32 trans_cursor_passive_bg_color;
uint32 split_cursor_active_bg_color;
uint32 split_cursor_passive_bg_color;
uint32 header_bg_color;
};
SplitRegister * xaccMallocSplitRegister (int type);
void xaccInitSplitRegister (SplitRegister *, int type);
void xaccConfigSplitRegister (SplitRegister *, int type);
void xaccDestroySplitRegister (SplitRegister *);
void xaccSetSplitRegisterColors (SplitRegisterColors reg_colors);
void xaccSplitRegisterConfigColors (SplitRegister *reg);
/* returns non-zero value if updates have been made to data */
unsigned int xaccSplitRegisterGetChangeFlag (SplitRegister *);

View File

@ -75,6 +75,7 @@ xaccInitTable (Table * table)
table->move_cursor = NULL;
table->traverse = NULL;
table->set_help = NULL;
table->client_data = NULL;
table->entries = NULL;
@ -85,6 +86,8 @@ xaccInitTable (Table * table)
table->user_data = NULL;
table->handlers = NULL;
table->alternate_bg_colors = GNC_F;
/* invalidate the "previous" traversed cell */
table->prev_phys_traverse_row = -1;
table->prev_phys_traverse_col = -1;
@ -376,7 +379,7 @@ makePassive (Table *table)
int phys_row = table->current_cursor_phys_row;
int phys_col = table->current_cursor_phys_col;
int r_origin, c_origin;
int virt_row;
/* Change the cell background colors to their "passive" values.
* This denotes that the cursor has left this location (which means more or
@ -390,21 +393,27 @@ makePassive (Table *table)
r_origin -= table->locators[phys_row][phys_col]->phys_row_offset;
c_origin -= table->locators[phys_row][phys_col]->phys_col_offset;
virt_row = table->locators[phys_row][phys_col]->virt_row;
curs = table->current_cursor;
for (i=0; i<curs->numRows; i++) {
for (j=0; j<curs->numCols; j++) {
BasicCell *cell;
/* yooooo hack alert -- the color capabilities for the cursor should
* be per-cell, not per cursor; so we do a quickie hack ughhh.
* first line is whatever was speced, the second line is white.
*/
if (0==i) {
table->bg_colors[i+r_origin][j+c_origin] = curs->passive_bg_color;
} else {
table->bg_colors[i+r_origin][j+c_origin] = 0xffffff;
}
uint32 color;
if (table->alternate_bg_colors) {
if ((virt_row % 2) == 1)
color = curs->passive_bg_color;
else
color = curs->passive_bg_color2;
}
else if (0 == i)
color = curs->passive_bg_color;
else
color = curs->passive_bg_color2;
table->bg_colors[i+r_origin][j+c_origin] = color;
cell = curs->cells[i][j];
if (cell) {
@ -935,14 +944,29 @@ gnc_table_enter_update(Table *table, int row, int col, int *cursor_position,
* different, freeing the old one. (Doing a strcmp would leak memory).
*/
if (retval && (val != retval)) {
if (safe_strcmp(retval, val) != 0)
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
if (table->entries[row][col]) free (table->entries[row][col]);
table->entries[row][col] = retval;
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
} else {
retval = NULL;
}
}
if (table->set_help)
{
BasicCell *cell;
char *help_str;
cell = arr->cells[rel_row][rel_col];
help_str = xaccBasicCellGetHelp(cell);
table->set_help(table, help_str, table->client_data);
if (help_str != NULL)
free(help_str);
}
/* record this position as the cell that will be
* traversed out of if a traverse even happens */
table->prev_phys_traverse_row = row;
@ -1017,7 +1041,8 @@ gnc_table_leave_update(Table *table, int row, int col,
/* ==================================================== */
const char *
gnc_table_modify_update(Table *table, int row, int col,
gnc_table_modify_update(Table *table,
int row, int col,
const char *oldval,
const char *change,
char *newval,
@ -1037,7 +1062,9 @@ gnc_table_modify_update(Table *table, int row, int col,
const char * (*mv) (BasicCell *,
const char *, const char *, const char *,
int *, int *, int *);
const char *retval = NULL;
ENTER ("gnc_table_modify_update()\n");
/* OK, if there is a callback for this cell, call it */
@ -1061,6 +1088,21 @@ gnc_table_modify_update(Table *table, int row, int col,
retval = newval;
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
}
if (table->set_help)
{
BasicCell *cell;
char *help_str;
cell = arr->cells[rel_row][rel_col];
help_str = xaccBasicCellGetHelp(cell);
table->set_help(table, help_str, table->client_data);
if (help_str != NULL)
free(help_str);
}
LEAVE ("gnc_table_modify_update(): "
"change %d %d (relrow=%d relcol=%d) cell=%p val=%s\n",
row, col, rel_row, rel_col,
@ -1071,6 +1113,54 @@ gnc_table_modify_update(Table *table, int row, int col,
/* ==================================================== */
gncBoolean
gnc_table_direct_update(Table *table,
int row, int col,
const char *oldval,
char **newval_ptr,
int *cursor_position,
int *start_selection,
int *end_selection,
void *gui_data)
{
CellBlock *arr = table->current_cursor;
const int rel_row = table->locators[row][col]->phys_row_offset;
const int rel_col = table->locators[row][col]->phys_col_offset;
BasicCell *cell = arr->cells[rel_row][rel_col];
gncBoolean result;
if (cell->direct_update == NULL)
return GNC_F;
result = cell->direct_update(cell, oldval, newval_ptr, cursor_position,
start_selection, end_selection, gui_data);
if ((*newval_ptr != oldval) && (*newval_ptr != NULL)) {
if (table->entries[row][col]) free (table->entries[row][col]);
table->entries[row][col] = *newval_ptr;
cell->changed = 0xffffffff;
}
if (table->set_help)
{
char *help_str;
help_str = xaccBasicCellGetHelp(cell);
table->set_help(table, help_str, table->client_data);
if (help_str != NULL)
free(help_str);
}
return result;
}
/* ==================================================== */
gncBoolean
gnc_table_find_valid_cell_horiz(Table *table, int *row, int *col,
gncBoolean exact_cell)

View File

@ -154,6 +154,10 @@ struct _RevLocator {
typedef struct _RevLocator RevLocator;
typedef void (*TableSetHelpFunc) (Table *table,
const char *help_str,
void *client_data);
/* The number of "physical" rows/cols is the number
* of displayed one-line gui rows/cols in the table.
@ -202,6 +206,8 @@ struct _Table {
int *p_new_phys_col,
void *client_data);
TableSetHelpFunc set_help;
void * client_data;
/* string values for each cell,
@ -214,6 +220,12 @@ struct _Table {
uint32 **bg_colors;
uint32 **fg_colors;
/* Determines whether the passive background
* colors alternate between odd and even virt
* rows, or between the first and non-first
* physical rows within cellblocks. */
gncBoolean alternate_bg_colors;
/* handler locators for each cell,
* of dimension num_phys_rows * num_phys_cols */
Locator ***locators;
@ -363,17 +375,20 @@ xaccRefreshCursorGUI (Table * table, gncBoolean do_scroll);
* However, don't just change it, because it will break functional code.
*/
const char *
gnc_table_enter_update(Table *table, int row, int col,
gnc_table_enter_update(Table *table,
int row, int col,
int *cursor_position,
int *start_selection,
int *end_selection);
const char *
gnc_table_leave_update(Table *table, int row, int col,
gnc_table_leave_update(Table *table,
int row, int col,
const char* old_text);
const char *
gnc_table_modify_update(Table *table, int row, int col,
gnc_table_modify_update(Table *table,
int row, int col,
const char *oldval,
const char *change,
char *newval,
@ -382,7 +397,18 @@ gnc_table_modify_update(Table *table, int row, int col,
int *end_selection);
gncBoolean
gnc_table_traverse_update(Table *table, int row, int col,
gnc_table_direct_update(Table *table,
int row, int col,
const char *oldval,
char **newval_ptr,
int *cursor_position,
int *start_selection,
int *end_selection,
void *gui_data);
gncBoolean
gnc_table_traverse_update(Table *table,
int row, int col,
gncTableTraversalDir dir,
int *dest_row,
int *dest_col);

View File

@ -60,7 +60,7 @@ xaccCreateTable (GtkWidget *widget, void *data)
GnucashSheet *sheet;
GnucashRegister *greg;
Table *table;
g_return_if_fail (widget != NULL);
g_return_if_fail (GNUCASH_IS_REGISTER (widget));
g_return_if_fail (data != NULL);
@ -76,7 +76,7 @@ xaccCreateTable (GtkWidget *widget, void *data)
gtk_widget_ref (table->table_widget);
/* config the cell-block styles */
sheet->cursor_style[GNUCASH_CURSOR_HEADER] =
gnucash_sheet_style_compile (sheet,
sr->header,
@ -107,8 +107,6 @@ xaccCreateTable (GtkWidget *widget, void *data)
gnucash_sheet_table_load (sheet);
gnucash_sheet_cursor_set_from_table (sheet, TRUE);
gnucash_sheet_redraw_all (sheet);
return;
}
@ -116,6 +114,8 @@ void
xaccRefreshTableGUI (Table * table)
{
GnucashSheet *sheet;
SheetBlockStyle *style;
SplitRegister *sr;
if (!table)
return;
@ -123,8 +123,29 @@ xaccRefreshTableGUI (Table * table)
return;
g_return_if_fail (GNUCASH_IS_SHEET (table->table_widget));
sheet = GNUCASH_SHEET(table->table_widget);
sr = (SplitRegister *)sheet->split_register;
style = sheet->cursor_style[GNUCASH_CURSOR_HEADER];
gnucash_sheet_style_recompile (style, sr->header, sr,
GNUCASH_CURSOR_HEADER);
style = sheet->cursor_style[GNUCASH_CURSOR_SINGLE];
gnucash_sheet_style_recompile (style, sr->single_cursor,
sr, GNUCASH_CURSOR_SINGLE);
style = sheet->cursor_style[GNUCASH_CURSOR_DOUBLE];
gnucash_sheet_style_recompile (style, sr->double_cursor,
sr, GNUCASH_CURSOR_DOUBLE);
style = sheet->cursor_style[GNUCASH_CURSOR_TRANS];
gnucash_sheet_style_recompile (style, sr->trans_cursor,
sr, GNUCASH_CURSOR_TRANS);
style = sheet->cursor_style[GNUCASH_CURSOR_SPLIT];
gnucash_sheet_style_recompile (style, sr->split_cursor,
sr, GNUCASH_CURSOR_SPLIT);
gnucash_sheet_table_load (sheet);

View File

@ -7,6 +7,20 @@
;; (use-modules (gnc))
(define (display-slib-error)
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
(newline)
(display "If you have slib installed, you may need to create\n")
(display "a symbolic link named 'slib' from the guile directory\n")
(display "(usually /usr/share/guile) to the directory where slib\n")
(display "is installed.\n\n")
(display "You may also need to run the following command as root:")
(newline)
(newline)
(display " guile -c \"(use-modules (ice-9 slib)) (require 'new-catalog)\"")
(newline)
(newline))
;; Test for slib.
(let* ((try-slib (lambda () (use-modules (ice-9 slib))))
(handler (lambda args #f))
@ -14,27 +28,22 @@
(if (not result)
(begin
(newline)
(display "It appears you do not have the 'slib' scheme\n")
(display "library installed. You need slib2c6 or later\n")
(display "It appears you do not have the 'slib' scheme ")
(display "library installed.\nYou need slib2c4 or later ")
(display "to run GnuCash.\n")
(newline)
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
(newline)
(display-slib-error)
(exit 1))))
;; This variable determines whether slib-backup.scm gets loaded.
(define gnc:*load-slib-backup* #f)
;; Test for slib >= 2c6.
(let* ((try-slib (lambda () (require 'printf) (sprintf #f "test")))
(handler (lambda args #f))
(result (catch #t try-slib handler)))
(if (not result)
(begin
(newline)
(display "It appears your 'slib' scheme library is out\n")
(display "of date. You need slib2c6 or later to run GnuCash.\n")
(newline)
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
(newline)
(exit 1))))
(set! gnc:*load-slib-backup* #t)))
(define (build-path firstelement . restofpath)

View File

@ -1,4 +1,3 @@
(use-modules (ice-9 slib))
(require 'hash-table)
(define gnc:register-c-side-scheme-ptr #f)
@ -22,3 +21,23 @@
(set! gnc:register-c-side-scheme-ptr register-c-side-scheme-ptr)
(set! gnc:unregister-c-side-scheme-ptr-id unregister-c-side-scheme-ptr-id))
(define (gnc:error->string tag args)
(define (write-error port)
(if (and (list? args) (not (null? args)))
(let ((func (car args)))
(if func
(begin
(display "Function: " port)
(display func port)
(display ", " port)
(display tag port)
(display "\n\n" port)))))
(false-if-exception
(apply display-error #f port args))
;; Here we should write the stack trace.
)
(false-if-exception
(call-with-output-string write-error)))

View File

@ -1,19 +1,105 @@
(gnc:support "extensions.scm")
(define (gnc:make-extension
;; The type of extension item, either 'menu, 'menu-item, or 'separator
type
;; The name of the extension in the menu
name
;; The tooltip
documentation-string
;; A list of names indicating the menus under which this item is
;; located. The last item indicates the item *after* which this
;; extension will go.
path
;; The script to call when the menu item is selected
script)
(vector type
name
documentation-string
path
script))
(define (gnc:extension-type extension)
(vector-ref extension 0))
(define (gnc:extension-name extension)
(vector-ref extension 1))
(define (gnc:extension-documentation extension)
(vector-ref extension 2))
(define (gnc:extension-path extension)
(vector-ref extension 3))
(define (gnc:extension-script extension)
(vector-ref extension 4))
(define (gnc:make-menu-item name documentation-string path script)
(gnc:make-extension 'menu-item name documentation-string path script))
(define (gnc:make-menu name path)
(gnc:make-extension 'menu name #f path #f))
(define (gnc:make-separator path)
(gnc:make-extension 'separator #f #f path #f))
(define (gnc:extensions-menu-setup win)
;; Should take window as a parameter?
(gnc:debug "Setting up extensions menu " win "\n")
(gnc:extensions-menu-add-item "Export data as text (Danger: Unfinished)"
"Export data as text."
(lambda ()
(gnc:main-win-export-data-as-text win)))
(gnc:extensions-menu-add-item "QIF File Import (Danger: Unfinished)"
"Import QIF File - Scripted in Guile."
(lambda ()
(gnc:extensions-qif-import win))))
(define menu (gnc:make-menu "Extensions" (list "_Settings")))
(gnc:hook-add-dangler gnc:*main-window-opened-hook* gnc:extensions-menu-setup)
(define export-item
(gnc:make-menu-item "Export data as text (Danger: Unfinished)"
"Export data as text."
(list "Extensions" "")
(lambda () (gnc:main-win-export-data-as-text win))))
(define qif-item
(gnc:make-menu-item "QIF File Import (Danger: Unfinished)"
"Import QIF File - Scripted in Guile."
(list "Extensions"
"Export data as text (Danger: Unfinished)")
(lambda () (gnc:extensions-qif-import win))))
(gnc:add-extension menu)
(gnc:add-extension export-item)
(gnc:add-extension qif-item))
;(gnc:hook-add-dangler gnc:*main-window-opened-hook* gnc:extensions-menu-setup)
;; Automatically pick accelerators for menu names
(define (gnc:new-menu-namer)
(define letter-hash (make-hash-table 23))
(define name-hash (make-hash-table 23))
(define (add-name name)
(define length (string-length name))
(define (try-at-k k)
(if (>= k length)
(begin
(hash-set! name-hash name name)
name)
(let* ((char (char-upcase (string-ref name k)))
(used (hash-ref letter-hash char)))
(if (not used)
(let ((new-name (string-append
(substring name 0 k)
"_"
(substring name k length))))
(hash-set! letter-hash char #t)
(hash-set! name-hash name new-name)
new-name)
(try-at-k (+ k 1))))))
(try-at-k 0))
(define (lookup name)
(hash-ref name-hash name))
(define (dispatch key)
(case key
((add-name) add-name)
((lookup) lookup)))
dispatch)

View File

@ -1,4 +1,3 @@
(define (gnc:startup)
(gnc:debug "starting up.")
(if (not (gnc:handle-command-line-args))
@ -14,10 +13,9 @@
;; Now we can load a bunch of files.
(gnc:depend "doc.scm")
(gnc:depend "extensions.scm") ; Should this be here or somewhere else?
(gnc:depend "extensions.scm")
(gnc:depend "text-export.scm")
(gnc:depend "importqif.scm")
(gnc:depend "test.scm")
(gnc:depend "report.scm")
;; FIXME: These do not belong here, but for now, we're putting them
@ -28,10 +26,18 @@
;;
;; Just load these since we might want to redefine them on the fly
;; and we're going to change this mechanism anyway...
(gnc:load "report/hello-world.scm")
(gnc:load "report/balance-and-pnl.scm")
(gnc:load "report/transaction-report.scm")
(gnc:load "report/average-balance.scm")
(let
((repdir
(opendir (string-append gnc:_share-dir-default_ "/scm/report"))))
(while (let ((cf (readdir repdir)))
(if (string? cf)
(if (and
(not (directory? cf))
(> (string-length cf) 4))
(if (string=? (substring cf (- (string-length cf) 4)
(string-length cf)) ".scm")
(gnc:load (string-append "report/" cf)))))
(string? cf)) ()))
;; Load the system configs
(if (not (gnc:load-system-config-if-needed))
@ -67,8 +73,8 @@
(gnc:ui-shutdown))))
(else
(gnc:hook-run-danglers gnc:*shutdown-hook*)
(gnc:ui-destroy)
(gnc:hook-run-danglers gnc:*shutdown-hook*)
(exit exit-status))))
(define (gnc:ui-finish)

View File

@ -69,6 +69,10 @@
(let ((getter (gnc:option-getter option)))
(getter)))
(define (gnc:option-default-value option)
(let ((getter (gnc:option-default-getter option)))
(getter)))
(define (gnc:restore-form-generator value->string)
(lambda () (string-append
"(lambda (option) "
@ -76,6 +80,10 @@
(value->string)
")))")))
(define (gnc:value->string value)
(call-with-output-string
(lambda (port) (write value port))))
(define (gnc:make-string-option
section
name
@ -83,7 +91,7 @@
documentation-string
default-value)
(let* ((value default-value)
(value->string (lambda () (string-append "\"" value "\""))))
(value->string (lambda () (gnc:value->string value))))
(gnc:make-option
section name sort-tag 'string documentation-string
(lambda () value)
@ -102,7 +110,7 @@
documentation-string
default-value)
(let* ((value default-value)
(value->string (lambda () (if value "#t" "#f"))))
(value->string (lambda () (gnc:value->string value))))
(gnc:make-option
section name sort-tag 'boolean documentation-string
(lambda () value)
@ -129,10 +137,8 @@
(and (pair? date) (exact? (car date)) (exact? (cdr date))))
(let* ((value (default-getter))
(value->string
(lambda ()
(string-append "(" (number->string (car value))
" . " (number->string (cdr value)) ")"))))
(value->string (lambda ()
(string-append "'" (gnc:value->string value)))))
(gnc:make-option
section name sort-tag 'date documentation-string
(lambda () value)
@ -200,7 +206,7 @@
(let* ((value default-value)
(value->string (lambda ()
(string-append "'" (symbol->string value)))))
(string-append "'" (gnc:value->string value)))))
(gnc:make-option
section name sort-tag 'multichoice documentation-string
(lambda () value)
@ -216,6 +222,100 @@
(list #f "multichoice-option: illegal choice")))
ok-values)))
;; number range options use the option-data as a list whose
;; elements are: (lower-bound upper-bound num-decimals step-size)
(define (gnc:make-number-range-option
section
name
sort-tag
documentation-string
default-value
lower-bound
upper-bound
num-decimals
step-size)
(let* ((value default-value)
(value->string (lambda () (number->string value))))
(gnc:make-option
section name sort-tag 'number-range documentation-string
(lambda () value)
(lambda (x) (set! value x))
(lambda () default-value)
(gnc:restore-form-generator value->string)
(lambda (x)
(cond ((not (number? x)) (list #f "number-range-option: not a number"))
((and (>= value lower-bound)
(<= value upper-bound))
(list #t x))
(else (list #f "number-range-option: out of range"))))
(list lower-bound upper-bound num-decimals step-size))))
;; Color options store rgba values in a list.
;; The option-data is a list, whose first element
;; is the range of possible rgba values and whose
;; second element is a boolean indicating whether
;; to use alpha transparency.
(define (gnc:make-color-option
section
name
sort-tag
documentation-string
default-value
range
use-alpha)
(define (canonicalize values)
(map exact->inexact values))
(define (values-in-range values)
(if (null? values)
#t
(let ((value (car values)))
(and (number? value)
(>= value 0)
(<= value range)
(values-in-range (cdr values))))))
(define (validate-color color)
(cond ((not (list? color)) (list #f "color-option: not a list"))
((not (= 4 (length color))) (list #f "color-option: wrong length"))
((not (values-in-range color))
(list #f "color-option: bad color values"))
(else (list #t color))))
(let* ((value (canonicalize default-value))
(value->string (lambda ()
(string-append "'" (gnc:value->string value)))))
(gnc:make-option
section name sort-tag 'color documentation-string
(lambda () value)
(lambda (x) (set! value (canonicalize x)))
(lambda () (canonicalize default-value))
(gnc:restore-form-generator value->string)
validate-color
(list range use-alpha))))
(define (gnc:color->html color range)
(define (html-value value)
(inexact->exact
(min 255.0
(truncate (* (/ 255.0 range) value)))))
(let ((red (car color))
(green (cadr color))
(blue (caddr color)))
(string-append
"#"
(number->string (html-value red) 16)
(number->string (html-value green) 16)
(number->string (html-value blue) 16))))
(define (gnc:color-option->html color-option)
(let ((color (gnc:option-value color-option))
(range (car (gnc:option-data color-option))))
(gnc:color->html color range)))
;; Create a new options database
(define (gnc:new-options)
@ -279,7 +379,8 @@
section-hash))
(hash-for-each
(lambda (section hash)
(section-thunk section hash)
(if section-thunk
(section-thunk section hash))
(if option-thunk
(section-for-each hash option-thunk)))
option-hash))
@ -302,16 +403,18 @@
(string-append "\n; Section: " section "\n\n")
port))
(lambda (option)
(let* ((generator (gnc:option-generate-restore-form option))
(restore-code (false-if-exception (generator))))
(if restore-code
(display
(generate-option-restore-form option restore-code)
port))))))
(let ((value (gnc:option-value option))
(default-value (gnc:option-default-value option)))
(if
(not (equal? value default-value))
(let* ((generator (gnc:option-generate-restore-form option))
(restore-code (false-if-exception (generator))))
(if restore-code
(display
(generate-option-restore-form option restore-code)
port))))))))
(let ((header "; GnuCash Configuration Options\n\n")
(forms (call-with-output-string generate-forms)))
(string-append header forms)))
(call-with-output-string generate-forms))
(define (register-callback section name callback)
(let ((id last-callback-id)
@ -344,16 +447,17 @@
(clear-changes))
(define (dispatch key)
(cond ((eq? key 'lookup) lookup-option)
((eq? key 'register-option) register-option)
((eq? key 'register-callback) register-callback)
((eq? key 'unregister-callback-id) unregister-callback-id)
((eq? key 'for-each) options-for-each)
((eq? key 'for-each-general) options-for-each-general)
((eq? key 'generate-restore-forms) generate-restore-forms)
((eq? key 'clear-changes) clear-changes)
((eq? key 'run-callbacks) run-callbacks)
(else (gnc:warn "options: bad key: " key "\n"))))
(case key
((lookup) lookup-option)
((register-option) register-option)
((register-callback) register-callback)
((unregister-callback-id) unregister-callback-id)
((for-each) options-for-each)
((for-each-general) options-for-each-general)
((generate-restore-forms) generate-restore-forms)
((clear-changes) clear-changes)
((run-callbacks) run-callbacks)
(else (gnc:warn "options: bad key: " key "\n"))))
dispatch)
@ -394,9 +498,10 @@
(gnc:option-db-register-option db_handle option))
options))
(define (gnc:save-options options options-string file)
(define (gnc:save-options options options-string file header)
(let ((code (gnc:generate-restore-forms options options-string))
(port (open file (logior O_WRONLY O_CREAT O_TRUNC))))
(if port (begin
(display header port)
(display code port)
(close port)))))

View File

@ -1,7 +1,6 @@
;;; $Id$
;;;;;;;;;;; QIF Parsing ;;;;;;;;;;;;;;
(use-modules (ice-9 slib))
(require 'hash-table)
(define qif-txn-list '())
@ -213,4 +212,4 @@
(display "trans-jumptable")
(display trans-jumptable)
(newline)
(newline)

View File

@ -1,6 +1,5 @@
;;;; Preferences...
(use-modules (ice-9 slib))
(require 'sort)
(require 'hash-table)
@ -58,11 +57,18 @@
(gnc:make-home-dir)
(gnc:save-options gnc:*options-entries*
(symbol->string 'gnc:*options-entries*)
(build-path (getenv "HOME") ".gnucash" "config.auto")))
(build-path (getenv "HOME") ".gnucash" "config.auto")
(string-append
"(gnc:config-file-format-version 1)\n\n"
"; GnuCash Configuration Options\n")))
(define (gnc:config-file-format-version version) #t)
;;;;;; Create default options and config vars
;; Account Types options
(gnc:register-configuration-option
(gnc:make-simple-boolean-option
"Account Types" "Show bank accounts"
@ -119,6 +125,8 @@
"k" "Show equity accounts in the account tree." #t))
;; Account Fields options
(gnc:register-configuration-option
(gnc:make-simple-boolean-option
"Account Fields" "Show account name"
@ -159,6 +167,9 @@
"Account Fields" "Show account balance"
"h" "Show the account balance column in the account tree." #t))
;; International options
(gnc:register-configuration-option
(gnc:make-multichoice-option
"International" "Date Format"
@ -166,8 +177,8 @@
(list #(us "US" "US-style: mm/dd/yyyy")
#(uk "UK" "UK-style dd/mm/yyyy")
#(ce "Europe" "Continental Europe: dd.mm.yyyy")
#(iso "ISO" "ISO Standard: yyyy-mm-dd")
#(locale "Locale" "Take from system locale"))))
#(iso "ISO" "ISO Standard: yyyy-mm-dd"))))
; #(locale "Locale" "Take from system locale"))))
;; hack alert - we should probably get the default new account currency
;; from the locale
@ -182,6 +193,9 @@
"International" "Use 24-hour time format"
"c" "Use a 24 hour (instead of a 12 hour) time format." #f))
;; Register options
(gnc:register-configuration-option
(gnc:make-multichoice-option
"Register" "Default Register Mode"
@ -200,15 +214,150 @@
"Register" "Auto-Raise Lists"
"b" "Automatically raise the list of accounts or actions during input." #t))
(gnc:register-configuration-option
(gnc:make-simple-boolean-option
"Register" "Show All Transactions"
"c" "By default, show every transaction in an account." #t))
(gnc:register-configuration-option
(gnc:make-number-range-option
"Register" "Number of Rows"
"d" "Default number of register rows to display."
15.0 ;; default
1.0 ;; lower bound
200.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
;; Register Color options
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Header background"
"a" "The header background color"
(list #xff #xff #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Single mode default even row background"
"b" "The default background color for even rows in single mode"
(list #xcc #xcc #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Single mode default odd row background"
"bb" "The default background color for odd rows in single mode"
(list #xcc #xcc #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Single mode active background"
"c" "The background color for the active transaction in single mode"
(list #xff #xdd #xdd 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Double mode default even row background"
"d" "The default background color for even rows in double mode"
(list #xcc #xcc #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Double mode default odd row background"
"e" "The default background color for odd rows in double mode"
(list #xff #xff #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-simple-boolean-option
"Register Colors" "Double mode colors alternate with transactions"
"ee" "Alternate the even and odd colors with each transaction, not each row"
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Double mode active background"
"f" "The background color for the active transaction in double mode"
(list #xff #xdd #xdd 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Multi mode default transaction background"
"g" "The default background color for transactions in multi-line mode and the auto modes"
(list #xcc #xcc #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Multi mode active transaction background"
"h" "The background color for an active transaction in multi-line mode and the auto modes"
(list #xff #xdd #xdd 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Multi mode default split background"
"i" "The default background color for splits in multi-line mode and the auto modes"
(list #xff #xff #xff 0)
255
#f))
(gnc:register-configuration-option
(gnc:make-color-option
"Register Colors" "Multi mode active split background"
"j" "The background color for an active split in multi-line mode and the auto modes"
(list #xff #xff #xdd 0)
255
#f))
;; General Options
(gnc:register-configuration-option
(gnc:make-simple-boolean-option
"General" "Save Window Geometry"
"a" "Save window sizes and positions." #t))
(gnc:register-configuration-option
(gnc:make-multichoice-option
"General" "Toolbar Buttons"
"a" "Choose whether to display icons, text, or both for toolbar buttons"
"b" "Choose whether to display icons, text, or both for toolbar buttons"
'icons_and_text
(list #(icons_and_text "Icons and Text" "Show both icons and text")
#(icons_only "Icons only" "Show icons only")
#(text_only "Text only" "Show text only"))))
(gnc:register-configuration-option
(gnc:make-multichoice-option
"General" "Account Separator"
"c" "The character used to separate fully-qualified account names"
'colon
(list #(colon ": (Colon)" "Income:Salary:Taxable")
#(slash "/ (Slash)" "Income/Salary/Taxable")
#(backslash "\\ (Backslash)" "Income\\Salary\\Taxable")
#(dash "- (Dash)" "Income-Salary-Taxable")
#(period ". (Period)" "Income.Salary.Taxable"))))
;; Configuation variables
(define gnc:*arg-show-version*
(gnc:make-config-var
"Show version."
@ -286,3 +435,87 @@ the current value of the path."
#f)))
equal?
'(default)))
;; Internal options -- Section names that start with "__" are not
;; displayed in option dialogs.
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "account_add_win_width" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "account_add_win_height" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "account_edit_win_width" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "account_edit_win_height" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "main_win_width" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "main_win_height" #f #f
400.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "reg_win_width" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))
(gnc:register-configuration-option
(gnc:make-number-range-option
"__gui" "reg_stock_win_width" #f #f
0.0 ;; default
0.0 ;; lower bound
32000.0 ;; upper bound
0.0 ;; number of decimals
1.0 ;; step size
))

View File

@ -1,4 +1,3 @@
(use-modules (ice-9 slib))
(require 'hash-table)
(gnc:support "report.scm")
@ -46,17 +45,25 @@
(call-report rendering-thunk options)))))
(define (gnc:report-menu-setup win)
;; This should be on a reports menu later...
(define menu (gnc:make-menu "_Reports" (list "_Settings")))
(define menu-namer (gnc:new-menu-namer))
(gnc:add-extension menu)
(hash-for-each
(lambda (name report)
(gnc:extensions-menu-add-item
(string-append "Report: " name)
(string-append "Display the " name " report.")
(lambda ()
(let ((options (false-if-exception (gnc:report-new-options report))))
(gnc:report-window (string-append "Report: " name)
(lambda () (gnc:run-report name options))
options)))))
(define item
(gnc:make-menu-item
((menu-namer 'add-name) name)
(string-append "Display the " name " report.")
(list "_Reports" "")
(lambda ()
(let ((options (false-if-exception (gnc:report-new-options report))))
(gnc:report-window (string-append "Report: " name)
(lambda () (gnc:run-report name options))
options)))))
(gnc:add-extension item))
*gnc:_report-info_*))
(define (gnc:define-report version name option-generator rendering-thunk)

View File

@ -1,43 +1,56 @@
;; -*-scheme-*-
;; average-balance.scm
;; Report history of account balance and other info
;; Also graphs the information with gnuplot
;; Matt Martin <mgmartin@abacusnet.net>
;; Plots the information with gnuplot
;;
;; Author makes no implicit or explicit guarantee of accuracy of
;; these calculations and accepts no responsibility for direct
;; or indirect losses incurred as a result of using this software.
;;
;; Note that this code uses functions defined in "transaction-report.scm"
;; Matt Martin <matt.martin@ieee.org>
(use-modules (ice-9 slib)(ice-9 regex))
(use-modules (ice-9 regex))
(require 'hash-table)
(require 'printf)
;hack alert - is this line necessary?
(gnc:depend "text-export.scm")
(gnc:depend "structure.scm")
(define datelist '())
;; Add delta to date, return result
(define (incdate adate delta)
;; Modify a date
(define (moddate op adate delta)
(let ((newtm (localtime (car adate))))
(begin
(set-tm:mday newtm (+ (tm:mday newtm) (tm:mday delta)))
(set-tm:mon newtm (+ (tm:mon newtm) (tm:mon delta)))
(set-tm:year newtm (+ (tm:year newtm) (tm:year delta)))
(set-tm:sec newtm (op (tm:sec newtm) (tm:sec delta)))
(set-tm:min newtm (op (tm:min newtm) (tm:min delta)))
(set-tm:hour newtm (op (tm:hour newtm) (tm:hour delta)))
(set-tm:mday newtm (op (tm:mday newtm) (tm:mday delta)))
(set-tm:mon newtm (op (tm:mon newtm) (tm:mon delta)))
(set-tm:year newtm (op (tm:year newtm) (tm:year delta)))
(let ((time (car (mktime newtm))))
(cons time 0))
))
)
;; actual recursion for date list building
;; Add or subtract time from a date
(define (decdate adate delta)(moddate - adate delta ))
(define (incdate adate delta)(moddate + adate delta ))
;; Time comparison, true if t2 is later than t1
(define (gnc:timepair-later t1 t2)
(< (car t1) (car t2)))
;; Build a list of time intervals
(define (dateloop curd endd incr)
(cond ((gnc:timepair-later-date curd endd)
(cons curd (dateloop (incdate curd incr) endd incr)))
(else (list curd))
(cond ((gnc:timepair-later curd endd)
(let ((nextd (incdate curd incr)))
(cons (list curd (decdate nextd SecDelta) '())
(dateloop nextd endd incr))))
(else '())
)
)
;; Create list of dates to report on
(define (generate-datelist beg nd stp)
(set! datelist (dateloop beg nd (eval stp))))
;; Options
(define (runavg-options-generator)
(define gnc:*runavg-track-options* (gnc:new-options))
@ -78,12 +91,24 @@
"d" "Do transaction report on this account"
(lambda ()
(let ((current-accounts (gnc:get-current-accounts))
(num-accounts (gnc:group-get-num-accounts (gnc:get-current-group)))
(first-account (gnc:group-get-account (gnc:get-current-group) 0)))
(cond ((not (null? current-accounts)) (list (car current-accounts)))
((> num-accounts 0) (list first-account))
(else ()))))
#f #f))
(num-accounts
(gnc:group-get-num-accounts (gnc:get-current-group))))
(cond ((not (null? current-accounts)) current-accounts)
(else
(let ((acctlist '()))
(gnc:for-loop
(lambda(x)
(set! acctlist
(append!
acctlist
(list (gnc:group-get-account
(gnc:get-current-group) x)))))
0 (eval num-accounts) 1)
acctlist
)
))))
#f #t))
(gnc:register-runavg-option
(gnc:make-multichoice-option
@ -96,16 +121,21 @@
#(YearDelta "Year" "Year")
)))
(gnc:register-runavg-option
(gnc:make-simple-boolean-option
"Report Options" "Sub-Accounts"
"e" "Add in sub-accounts of each selected" #f))
(gnc:register-runavg-option
(gnc:make-multichoice-option
"Report Options" "Plot Type"
"b" "Get number at each one of these" 'NoPlot
"f" "Get number at each one of these" 'NoPlot
(list #(NoPlot "Nothing" "Make No Plot")
#(AvgBalPlot "Average" "Average Balance")
#(GainPlot "Net Gain" "Net Gain")
#(GLPlot "Gain/Loss" "Gain And Loss")
)))
gnc:*runavg-track-options*)
; A reference zero date
@ -121,6 +151,9 @@
zd
))
(define SecDelta (let ((ddt (eval zdate)))
(set-tm:sec ddt 1)
ddt))
(define YearDelta (let ((ddt (eval zdate)))
(set-tm:year ddt 1)
ddt))
@ -139,12 +172,13 @@
(set-tm:mon ddt 1)
ddt))
(define AvgBalPlot "using 1:2:3:4 t 'Average Balance' with errorbars")
(define GainPlot "using 1:5 t 'Net Gain' with linespoints")
(define GLPlot "using 1:7 t 'Losses' with lp, '' using 1:6 t 'Gains' with lp")
;; Plot strings
(define AvgBalPlot "using 2:3:4:5 t 'Average Balance' with errorbars, '' using 2:3 smooth sbezier t '' with lines")
(define GainPlot "using 2:6 t 'Net Gain' with linespoints, '' using 2:6 smooth sbezier t '' with lines" )
(define GLPlot "using 2:8 t 'Losses' with lp, '' using 2:7 t 'Gains' with lp")
(define NoPlot "")
;;; applies thunk to each split in account account
;; applies thunk to each split in account account
(define (gnc:for-each-split-in-account account thunk)
(gnc:for-loop (lambda (x) (thunk (gnc:account-get-split account x)))
0 (gnc:account-get-split-count account) 1))
@ -163,30 +197,14 @@
(define (gnc:split-get-account-name split)
(gnc:account-get-name (gnc:split-get-account split)))
;; timepair manipulation functions
;; hack alert - these should probably be put somewhere else
;; and be implemented PROPERLY rather than hackily
(define (gnc:timepair-to-datestring tp)
(define (gnc:timepair-to-ldatestring tp)
(let ((bdtime (localtime (car tp))))
(strftime "%m/%d/%Y" bdtime)))
;; Find difference in seconds (?) between time 1 and time2
(define (gnc:timepair-delta t1 t2)
(let ((time1 (car (gnc:timepair-canonical-day-time t1)))
(time2 (car (gnc:timepair-canonical-day-time t2))))
(- time2 time1)))
;; Don't know if these can be local+static to reduce-split-list
(define tempmax -1E10)
(define tempmin 1E10)
(define last 0)
(define zdate (cons 0 0))
(define prevdate zdate)
(define avgaccum 0)
(define lossaccum 0)
(define gainaccum 0)
(- (car t2) (car t1)))
; Convert to string
(define (tostring val)
@ -205,11 +223,13 @@
; Create an html table row from a list of entries
(define (html-table-row lst)
(string-append
(sprintf #f "<TR>")
(apply string-append (map html-table-col lst))
(sprintf #f "</TR>\n")
)
(cond ((string? lst) lst)
(else
(string-append
(sprintf #f "<TR>")
(apply string-append (map html-table-col lst))
(sprintf #f "</TR>\n")
)))
)
; Create an html table from a list of rows, each containing
@ -227,7 +247,7 @@
)
(define (html-table-header vec)
(apply string-append "<TABLE cellspacing=10>" (map html-table-headcol vec))
(apply string-append "<TABLE cellspacing=10 rules=\"rows\">\n" (map html-table-headcol vec))
)
(define (html-table-footer)
@ -274,89 +294,199 @@
)
)
;; Reset accumulators between time intervals
(define (resetvals bal curdate)
(set! tempmax bal)
(set! tempmin bal)
(set! prevdate curdate)
(set! avgaccum 0)
(set! lossaccum 0)
(set! gainaccum 0)
)
;; Returns sum of all vector elements after the first
(define (vector-sum v)
(let ((sum 0))
(gnc:for-loop (lambda(i) (set! sum (+ sum (car (vector-ref v i)))))
1 (vector-length v) 1)
sum))
;
; Reduce a list of splits tl to a list of values at each date in datelist dl
;
(define (reduce-split-list dl tl pt)
(cond ((null? dl) '()) ;; End of recursion
; Datelist entry operators
(define (dl:begin dl) (car dl))
(define (dl:end dl) (car (cdr dl)))
(define (reduce-split-list dl tl pt av)
(let ((avgaccum 0)
(bals av)
(prevdate 0)
(balmin 10E9)
(balmax -10E9)
(gains 0)
(losses 0))
(else (let* ((bal last) ;; get Balance and datelist "time"
(ct (car dl))
(val 0))
(define (procvals)
(let ((curbal (vector-sum (car (cdr (av 'x 0))))))
(set! balmin (min balmin curbal))
(set! balmax (max balmax curbal))))
(begin
(cond ( (not (null? tl))
;; Get latest split values if any remain
(set! bal (gnc:split-get-balance (car tl)))
(set! val (gnc:split-get-value (car tl)))
(set! ct (gnc:split-get-transaction-date (car tl)))
))
(define (accbal beg end)
(let ((curbal (vector-sum (car (cdr (av 'x 0))))))
(set! avgaccum (+ avgaccum
(* curbal
(gnc:timepair-delta beg end)))))
)
(cond ; past time interval bound ?
((or(gnc:timepair-later-date (car dl) ct ) (null? tl))
(cond ; Is this the first interval ?
((= (car zdate) (car prevdate) )
; Start first date interval
(begin
(resetvals bal (car dl))
(reduce-split-list (cdr dl) tl (car dl))
)
(define (calc-in-interval d tl)
(cond ((not (null? tl))
(let* ((bd (dl:begin d)) ; begin date
(ed (dl:end d)) ; end date
(cs (car tl)) ; current split
(cd (gnc:split-get-transaction-date cs)) ;current date
(an (gnc:split-get-account-name cs)) ; account name
(prevbal (vector-sum (car (cdr (av 'x 0))))))
(cond ((gnc:timepair-later cd bd) ;split before interval
(bals 'put an (gnc:split-get-balance cs))
(calc-in-interval d (cdr tl))
)
(else
(set! avgaccum ; sum up to now
(+ avgaccum
(* last (gnc:timepair-delta pt (car dl)))))
(cons ; form list of values for one "row"
(list
(gnc:timepair-to-datestring (car dl))
(let ((dlta (gnc:timepair-delta prevdate (car dl))))
(cond ((= dlta 0) 0); Should never happen !
((= avgaccum 0) bal)
(else (/ avgaccum dlta))))
tempmax
tempmin
(- gainaccum lossaccum)
gainaccum
lossaccum
)
(begin
(resetvals last (car dl))
(reduce-split-list (cdr dl) tl (car dl))
)
)
)))
(else ; mid-interval
(begin
(set! tempmax (max tempmax bal))
(set! tempmin (min tempmin bal))
(set! avgaccum
(+ avgaccum
(* last (gnc:timepair-delta pt ct))))
(cond ((> val 0) (set! gainaccum (+ gainaccum val)))
(else (set! lossaccum (- lossaccum val)))
)
(set! last bal)
(reduce-split-list dl (cdr tl) ct)
))
)
)))))
((gnc:timepair-later cd ed) ;split is in the interval
(accbal prevdate cd)
(procvals)
(bals 'put an (gnc:split-get-balance cs))
(let ((val (gnc:split-get-value cs)))
(cond ((< 0 val) (set! gains (+ gains val)))
(else (set! losses (- losses val)))))
(procvals) ; catch all cases
(set! prevdate cd)
(calc-in-interval d (cdr tl))
)
(else ; Past interval, nothing to do?
(accbal prevdate ed)
(procvals)
tl
)
)))
(else ; Out of data !
(accbal prevdate (dl:end d))
(procvals)
tl
)
)
)
;; Actual routine
(cond ((null? dl) '()) ;; End of recursion
(else
(let* ((bd (dl:begin (car dl)))
(ed (dl:end (car dl))) )
;; Reset valaccumulator values
(set! prevdate bd)
(set! avgaccum 0)
(set! gains 0)
(set! losses 0)
(let* ((rest (calc-in-interval (car dl) tl)))
;; list of values for report
(cons
(list
(gnc:timepair-to-ldatestring bd)
(gnc:timepair-to-ldatestring ed)
(/ avgaccum
(gnc:timepair-delta bd ed))
balmin balmax (- gains losses) gains losses)
(reduce-split-list (cdr dl) rest pt av)))
)
)
)))
;; Pull a scheme list of splits from a C array
(define (gnc:convert-split-list slist)
(let ((numsplit 0)
(schsl '()))
(while
(let ((asplit (gnc:ith-split slist numsplit)))
(cond
((pointer-token-null? asplit ) #f)
(else
(set! schsl (append! schsl (list asplit)) )
(set! numsplit (+ numsplit 1))
#t))) ())
schsl
)
)
;; Pull a scheme list of accounts (including subaccounts) from group grp
(define (gnc:group-get-account-list grp)
(cond ((pointer-token-null? grp) '())
(else
(let ((numacct 0)
(acctar (gnc:get-accounts grp))
(schal '()))
(while
(let ((anact (gnc:account-nth-account acctar numacct)))
(cond
((pointer-token-null? anact ) #f)
(else
(set! schal (append! schal (list anact)) )
(set! numacct (+ numacct 1))
#t))) ())
schal
)))
)
(define (accumvects x y)
(cond
((null? x) '())
((number? (car x))
(cons (+ (car x) (car y)) (accumvects (cdr x) (cdr y))))
(else (cons "x" (accumvects (cdr x) (cdr y)))))
)
;; Add x to list lst if it is not already in there
(define (addunique lst x)
(cond
((null? lst) (list x)) ; all checked add it
(else (cond
((equal? x (car lst)) lst) ; found, quit search and don't add again
(else (cons (car lst) (addunique (cdr lst) x))) ; keep searching
))))
;; Calculate averages of each column
(define (get-averages indata)
(let* ((avglst '()))
(map (lambda (x) (set! avglst (append avglst (list 0.0)))) (car indata))
(map (lambda (x)
(set! avglst (accumvects x avglst)))
indata)
(map (lambda (x)
(cond ((number? x) (/ x (length indata)))
(else "")))
avglst)
))
;; Turn a C array of accounts into a scheme list of account names
(define (gnc:acctnames-from-list acctlist)
(let ((anlist '()))
(map (lambda(an)
(set! anlist (append! anlist
(list (gnc:account-get-name an))))) acctlist)
anlist))
(define acctcurrency "USD")
(define acctname "")
(define (allsubaccounts accounts)
(cond ((null? accounts) '())
(else
; (display (gnc:account-get-name (car accounts)))(newline)
(append
(gnc:group-get-account-list
(gnc:account-get-children (car accounts)))
(allsubaccounts (cdr accounts))))))
(gnc:define-report
;; version
1
@ -369,8 +499,10 @@
(let* (
(begindate (gnc:option-value
(gnc:lookup-option options "Report Options" "From")))
(enddate (gnc:lookup-option options "Report Options" "To"))
(stepsize (gnc:lookup-option options "Report Options" "Step Size"))
(enddate (gnc:option-value
(gnc:lookup-option options "Report Options" "To")))
(stepsize (gnc:option-value
(gnc:lookup-option options "Report Options" "Step Size")))
(plotstr (gnc:option-value
(gnc:lookup-option options "Report Options" "Plot Type")))
@ -378,45 +510,94 @@
(accounts (gnc:option-value
(gnc:lookup-option options
"Report Options" "Account")))
(dosubs (gnc:option-value
(gnc:lookup-option options
"Report Options" "Sub-Accounts")))
(prefix (list "<HTML>" "<BODY>"))
(suffix (list "</BODY>" "</HTML>"))
(collist
(list "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss"))
(list "Beginning" "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss"))
(report-lines '())
(rept-data '())
(sum-data '())
(tempstruct '())
(rept-text "")
(gncq (gnc:malloc-query))
(slist '())
)
(generate-datelist
begindate
(gnc:option-value enddate)
(gnc:option-value stepsize))
(gnc:init-query gncq)
(if (null? accounts)
(set! report-lines
(list "<TR><TD>You have not selected an account.</TD></TR>"))
(begin
; Grab account names
(set! acctname (gnc:account-get-name (car accounts)))
(set! acctcurrency (gnc:account-get-currency (car accounts)))
(gnc:for-each-split-in-account
(car accounts)
(lambda (split)
(set! report-lines
(append! report-lines (list split)))))))
(map (lambda(an)
(set! acctname
(string-append
acctname
" , "
(gnc:account-get-name an))))
(cdr accounts) )
(cond ((equal? dosubs #t)
(map (lambda (a)
(set! accounts (addunique accounts a)))
(allsubaccounts accounts))
(set! acctname (string-append acctname " and sub-accounts"))
))
(map (lambda(acct) (gnc:query-add-account gncq acct)) accounts)
(set! tempstruct
(build-mystruct-instance
(define-mystruct
(gnc:acctnames-from-list accounts))))
(set! acctcurrency (gnc:account-get-currency (car accounts)))
(set! report-lines
(gnc:convert-split-list (gnc:query-get-splits gncq)))))
(gnc:free-query gncq)
(display (length report-lines))
(display " Splits\n")
(set! prevdate zdate)
(set! rept-data (reduce-split-list datelist report-lines (car datelist)))
; Set initial balances to zero
(map (lambda(an) (tempstruct 'put an 0))
(gnc:acctnames-from-list accounts))
(dateloop begindate
enddate
(eval stepsize))
(set! rept-data
(reduce-split-list
(dateloop begindate
enddate
(eval stepsize))
report-lines zdate tempstruct))
(set! sum-data (get-averages rept-data))
;; Create HTML
(set! rept-text
(html-table
collist
rept-data))
(append rept-data
(list "<TR cellspacing=0><TD><TD><TD colspan=3><HR size=2 noshade><TD colspan=3><HR size=2 noshade></TR>" sum-data))))
;; Do a plot
(if (not (equal? NoPlot (eval plotstr)))
(let* ((fn "/tmp/gncplot.dat")
(preplot (string-append
@ -435,6 +616,6 @@
(string-append "echo \"" preplot "plot '" fn "'" (eval plotstr)
"\"|gnuplot -persist " )))
)
(append prefix (list rept-text) suffix)))
(append prefix (list "Report for " acctname "<p>\n" )
(list rept-text) suffix)))
)

View File

@ -1,8 +1,5 @@
;; -*-scheme-*-
(use-modules (ice-9 slib))
(require 'stdio)
(gnc:depend "text-export.scm")
(let ()

View File

@ -1,27 +1,27 @@
;; I haven't finished converting this yet...
(gnc:define-report
;(gnc:define-report
;; version
1
; 1
;; Menu name
"Folio"
; "Folio"
;; Options Generator
#f
; #f
;; Rendering thunk. See report.scm for details.
(lambda (options)
(list
"<html>"
"<head>"
"<title>Portfolio Valuation</title>"
"</head>"
; (lambda (options)
; (list
; "<html>"
; "<head>"
; "<title>Portfolio Valuation</title>"
; "</head>"
"<body bgcolor=#ccccff>"
"This page shows the valuation of your stock/mutual fund portfolio."
"<br>"
"You can create custom reports by editing the file"
"<tt>Reports/report-folio.phtml</tt>"
"<p>"
; "<body bgcolor=#ccccff>"
; "This page shows the valuation of your stock/mutual fund portfolio."
; "<br>"
; "You can create custom reports by editing the file"
; "<tt>Reports/report-folio.phtml</tt>"
; "<p>"
;; currency symbol that is printed is a dollar sign, for now
;; currency amounts get printed with two decimal places
@ -34,130 +34,125 @@
;; This rouine accepts a pointer to a group, returns
;; a flat list of all of the children in the group.
sub account_flatlist
{
local ($grp) = $_[0];
local ($naccts) = gnucash::xaccGroupGetNumAccounts ($grp);
local ($n);
local (@acctlist, @childlist);
local ($children);
;sub account_flatlist
;{
; local ($grp) = $_[0];
; local ($naccts) = gnucash::xaccGroupGetNumAccounts ($grp);
; local ($n);
; local (@acctlist, @childlist);
; local ($children);
foreach $n (0..$naccts-1) {
$acct = gnucash::xaccGroupGetAccount ($grp, $n);
push (@acctlist, $acct);
$children = gnucash::xaccAccountGetChildren ($acct);
if ($children) {
@childlist = &account_flatlist ($children);
push (@acctlist, @childlist);
}
}
; foreach $n (0..$naccts-1) {
; $acct = gnucash::xaccGroupGetAccount ($grp, $n);
; push (@acctlist, $acct);
; $children = gnucash::xaccAccountGetChildren ($acct);
; if ($children) {
; @childlist = &account_flatlist ($children);
; push (@acctlist, @childlist);
; }
; }
return (@acctlist);
}
; return (@acctlist);
;}
;; --------------------------------------------------
;; $split = &get_last_split ($account);
;; returns the most recent split in the account.
sub get_last_split
{
local ($acct) = $_[0];
local ($query, $splitlist, $split);
;sub get_last_split
;{
; local ($acct) = $_[0];
; local ($query, $splitlist, $split);
$query = gnucash::xaccMallocQuery();
gnucash::xaccQueryAddAccount ($query, $acct);
gnucash::xaccQuerySetMaxSplits ($query, 1);
$splitlist = gnucash::xaccQueryGetSplits ($query);
; $query = gnucash::xaccMallocQuery();
; gnucash::xaccQueryAddAccount ($query, $acct);
; gnucash::xaccQuerySetMaxSplits ($query, 1);
; $splitlist = gnucash::xaccQueryGetSplits ($query);
$split = gnucash::IthSplit ($splitlist, 0);
}
; $split = gnucash::IthSplit ($splitlist, 0);
;}
;; --------------------------------------------------
;; get a flat list of all the accounts ...
@acclist = &account_flatlist ($topgroup);
;@acclist = &account_flatlist ($topgroup);
;; get the most recent price date ..
$latest = -1.0e20;
$earliest = 1.0e20;
foreach $acct (@acclist)
{
$accntype = &gnucash::xaccAccountGetType($acct);
if (($accntype == $gnucash::STOCK) ||
($accntype == $gnucash::MUTUAL)) {
$split = &get_last_split ($acct);
$trans = gnucash::xaccSplitGetParent ($split);
$secs = gnucash::xaccTransGetDate ($trans);
if ($latest < $secs) { $latest = $secs; }
if ($earliest > $secs) { $earliest = $secs; }
}
}
;$latest = -1.0e20;
;$earliest = 1.0e20;
;foreach $acct (@acclist)
;{
; $accntype = &gnucash::xaccAccountGetType($acct);
; if (($accntype == $gnucash::STOCK) ||
; ($accntype == $gnucash::MUTUAL)) {
; $split = &get_last_split ($acct);
; $trans = gnucash::xaccSplitGetParent ($split);
; $secs = gnucash::xaccTransGetDate ($trans);
; if ($latest < $secs) { $latest = $secs; }
; if ($earliest > $secs) { $earliest = $secs; }
; }
;}
$ldayte = gnucash::xaccPrintDateSecs ($latest);
$edayte = gnucash::xaccPrintDateSecs ($earliest);
;$ldayte = gnucash::xaccPrintDateSecs ($latest);
;$edayte = gnucash::xaccPrintDateSecs ($earliest);
:>
<table cellpadding=1>
<caption><b>Stock Portfolio Valuation</b>
<br>Earliest Price <:= $edayte :> &nbsp; &nbsp; Latest Price <:= $ldayte :>
</caption>
<tr>
<th>Name
<th>Ticker
<th align=center>Shares
<th align=center>Recent Price
<th align=center>Value
<th align=center>Cost
<th align=center>Profit/Loss
;<table cellpadding=1>
;<caption><b>Stock Portfolio Valuation</b>
;<br>Earliest Price <:= $edayte :> &nbsp; &nbsp; Latest Price <:= $ldayte :>
;</caption>
;<tr>
;<th>Name
;<th>Ticker
;<th align=center>Shares
;<th align=center>Recent Price
;<th align=center>Value
;<th align=center>Cost
;<th align=center>Profit/Loss
<:
;$totvalue = 0;
;$totcost = 0;
$totvalue = 0;
$totcost = 0;
;foreach $acct (@acclist)
;{
foreach $acct (@acclist)
{
; $accntype = &gnucash::xaccAccountGetType($acct);
; if (($accntype == $gnucash::STOCK) ||
; ($accntype == $gnucash::MUTUAL)) {
$accntype = &gnucash::xaccAccountGetType($acct);
if (($accntype == $gnucash::STOCK) ||
($accntype == $gnucash::MUTUAL)) {
; $accname = &gnucash::xaccAccountGetName($acct);
; $ticker = &gnucash::xaccAccountGetSecurity ($acct);
; $accbaln = &gnucash::xaccAccountGetBalance($acct);
$accname = &gnucash::xaccAccountGetName($acct);
$ticker = &gnucash::xaccAccountGetSecurity ($acct);
$accbaln = &gnucash::xaccAccountGetBalance($acct);
; $split = &get_last_split ($acct);
; $price = gnucash::xaccSplitGetSharePrice ($split);
; $shares = gnucash::xaccSplitGetShareBalance ($split);
; $value = gnucash::xaccSplitGetBalance ($split);
; $cost = gnucash::xaccSplitGetCostBasis ($split);
; $profit = $accbaln - $cost;
$split = &get_last_split ($acct);
$price = gnucash::xaccSplitGetSharePrice ($split);
$shares = gnucash::xaccSplitGetShareBalance ($split);
$value = gnucash::xaccSplitGetBalance ($split);
$cost = gnucash::xaccSplitGetCostBasis ($split);
$profit = $accbaln - $cost;
; $totvalue += $value;
; $totcost += $cost;
$totvalue += $value;
$totcost += $cost;
; print "<tr><td>$accname";
; print "<td>$ticker";
; printf "<td align=right nowrap>%10.3f", $shares;
; printf "<td align=right nowrap>\$%10.2f\n", $price;
; printf "<td align=right nowrap>\$%10.2f\n", $value;
; printf "<td align=right nowrap>\$%10.2f\n", $cost;
; printf "<td align=right nowrap>\$%10.2f\n", $profit;
; }
;}
print "<tr><td>$accname";
print "<td>$ticker";
printf "<td align=right nowrap>%10.3f", $shares;
printf "<td align=right nowrap>\$%10.2f\n", $price;
printf "<td align=right nowrap>\$%10.2f\n", $value;
printf "<td align=right nowrap>\$%10.2f\n", $cost;
printf "<td align=right nowrap>\$%10.2f\n", $profit;
}
}
;print "<tr><td>&nbsp;<td>&nbsp;<td>&nbsp;\n"; ;; blank line
;print "<td>&nbsp;<td>&nbsp;<td>&nbsp;\n"; ;; blank line
print "<tr><td>&nbsp;<td>&nbsp;<td>&nbsp;\n"; ;; blank line
print "<td>&nbsp;<td>&nbsp;<td>&nbsp;\n"; ;; blank line
;print "<tr><td><b>Net</b><td>&nbsp;";
;print "<td>&nbsp;<td>&nbsp;";
;printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totvalue;
;printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totcost;
;printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totvalue-$totcost;
print "<tr><td><b>Net</b><td>&nbsp;";
print "<td>&nbsp;<td>&nbsp;";
printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totvalue;
printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totcost;
printf "<td align=right nowrap>&nbsp;&nbsp;<u>\$%10.2f</u> \n", $totvalue-$totcost;
:>
</table>
</body>
</html>
;</table>
;</body>
;</html>

View File

@ -21,7 +21,7 @@
(define (gnc:register-dummy-option new-option)
(gnc:register-option gnc:*dummy-options* new-option))
;; This is a boolean option. It is in Section 'Page One'
;; This is a boolean option. It is in Section 'Hello, World!'
;; and is named 'Boolean Option'. Its sorting key is 'a',
;; thus it will come before options with sorting keys
;; 'b', 'c', etc. in the same section. The default value
@ -30,7 +30,7 @@
;; the mouse pointer over the option.
(gnc:register-dummy-option
(gnc:make-simple-boolean-option
"Page One" "Boolean Option"
"Hello, World!" "Boolean Option"
"a" "This is a boolean option." #t))
;; This is a multichoice option. The user can choose between
@ -40,8 +40,8 @@
;; value is 'third.
(gnc:register-dummy-option
(gnc:make-multichoice-option
"Page Two" "Multi Choice Option"
"a" "This is a multi choice option." 'third
"Hello, World!" "Multi Choice Option"
"b" "This is a multi choice option." 'third
(list #(first "First Option" "Help for first option.")
#(second "Second Option" "Help for second option.")
#(third "Third Option" "Help for third option.")
@ -54,8 +54,8 @@
;; other key is 'a'.
(gnc:register-dummy-option
(gnc:make-string-option
"Page Two" "String Option"
"b" "This is a string option" "Hello, World"))
"Hello, World!" "String Option"
"c" "This is a string option" "Hello, World"))
;; This is a date/time option. The user can pick a date and,
;; possibly, a time. Times are stored as a pair
@ -65,8 +65,8 @@
;; time.
(gnc:register-dummy-option
(gnc:make-date-option
"Time and Date" "Just a Date Option"
"a" "This is a date option"
"Hello, World!" "Just a Date Option"
"d" "This is a date option"
(lambda () (cons (current-time) 0))
#f))
@ -74,11 +74,26 @@
;; the time.
(gnc:register-dummy-option
(gnc:make-date-option
"Time and Date" "Time and Date Option"
"b" "This is a date option with time"
"Hello, World!" "Time and Date Option"
"e" "This is a date option with time"
(lambda () (cons (current-time) 0))
#t))
;; This is a color option, defined by rgba values. A color value
;; is a list where the elements are the red, green, blue, and
;; alpha channel values respectively. The penultimate argument
;; (255) is the allowed range of rgba values. The final argument
;; (#f) indicates the alpha value should be ignored. You can get
;; a color string from a color option with gnc:color-option->html,
;; which will scale the values appropriately according the range.
(gnc:register-dummy-option
(gnc:make-color-option
"Hello, World!" "Background Color"
"f" "This is a color option"
(list #x99 #xcc #xff 0)
255
#f))
;; This is an account list option. The user can select one
;; or (possibly) more accounts from the list of accounts
;; in the current file. Values are scheme handles to actual
@ -96,11 +111,20 @@
;; selected account in the main window, if any.
(gnc:register-dummy-option
(gnc:make-account-list-option
"Page One" "An account list option"
"b" "This is an account list option"
"Hello, World!" "An account list option"
"g" "This is an account list option"
(lambda () (gnc:get-current-accounts))
#f #t))
;; This option is for testing. When true, the report generates
;; an exception.
(gnc:register-dummy-option
(gnc:make-simple-boolean-option
"Testing" "Crash the report"
"a" (string-append "This is for testing. "
"Your reports probably shouldn't have an "
"option like this.") #f))
gnc:*dummy-options*)
;; This is a helper function to generate an html list of account names
@ -138,33 +162,43 @@
;; options in the set of options given to the function. This set will
;; be generated by the options generator above.
;; Use (gnc:lookup-option options section name) to get the option.
(let ((boolop (gnc:lookup-option options "Page One" "Boolean Option"))
(let ((boolop (gnc:lookup-option options
"Hello, World!" "Boolean Option"))
(multop (gnc:lookup-option options
"Page Two" "Multi Choice Option"))
(strop (gnc:lookup-option options "Page Two" "String Option"))
"Hello, World!" "Multi Choice Option"))
(strop (gnc:lookup-option options
"Hello, World!" "String Option"))
(dateop (gnc:lookup-option options
"Time and Date" "Just a Date Option"))
"Hello, World!" "Just a Date Option"))
(dateop2 (gnc:lookup-option options
"Time and Date" "Time and Date Option"))
"Hello, World!" "Time and Date Option"))
(colorop (gnc:lookup-option options
"Hello, World!" "Background Color"))
(account-list-op (gnc:lookup-option options
"Page One"
"An account list option")))
(let ((time-string (strftime "%c" (localtime (current-time))))
"Hello, World!"
"An account list option"))
(crash-op (gnc:lookup-option options "Testing" "Crash the report")))
(let ((time-string (strftime "%X" (localtime (current-time))))
(date-string (strftime "%x" (localtime (car (gnc:option-value
dateop)))))
(date-string2 (strftime "%c"
(date-string2 (strftime "%x %X"
(localtime (car (gnc:option-value
dateop2))))))
;; Crash if asked to.
(if (gnc:option-value crash-op)
(string-length #f)) ;; this will crash
;; Here's where we generate the html. A real report would need
;; much more code and involve many more utility functions. See
;; the other reports for details. Note that you can used nested
;; lists here, as well as arbitrary functions.
(list
"<html>"
"<body>"
"<body bgcolor=" (gnc:color-option->html colorop) ">"
"<h2>Hello, World Report</h2>"
"<h2>Hello, World</h2>"
(list "<p>"
"This is a sample GnuCash report. "

View File

@ -3,8 +3,6 @@
;; Report on all transactions in an account
;; Robert Merkel (rgmerk@mira.net)
(use-modules (ice-9 slib))
(require 'printf)
(require 'sort)
;hack alert - is this line necessary?
@ -215,7 +213,7 @@
(define (gnc:tr-report-get-first-acc-name split-scm)
(let ((other-splits (gnc:tr-report-get-other-splits split-scm)))
(cond ((= (length other-splits) 0) "")
(cond ((= (length other-splits) 0) "-")
(else (caar other-splits)))))
;;; something like

1212
src/scm/slib-backup.scm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,9 @@
;; None of these loads will be affected by any command line arguments
;; since arguments aren't parsed until gnc:main is executed.
(if gnc:*load-slib-backup*
(gnc:load "slib-backup.scm"))
(gnc:load "macros.scm")
(gnc:load "config-var.scm")
(gnc:load "utilities.scm")

View File

@ -38,6 +38,8 @@
#define HH_ADJBWIN "xacc-adjbwin.html"
#define HH_MAIN "xacc-main.html"
#define HH_GPL "xacc-gpl.html"
#define HH_GLOBPREFS "xacc-globalprefs.html"
#define HH_ACCEDIT "xacc-accountedit.html"
/** STRUCTS *********************************************************/