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

View File

@ -32,6 +32,7 @@
#include "SplitLedger.h" #include "SplitLedger.h"
#include "Transaction.h" #include "Transaction.h"
/* the MAX_QUERY_SPLITS define determines how many transactions should be shown /* 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 * 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. * into a user-configurable value. So hack-alert on the configuration aspect.
@ -72,6 +73,7 @@ struct _xaccLedgerDisplay {
void (*redraw) (xaccLedgerDisplay *); /* redraw callback */ void (*redraw) (xaccLedgerDisplay *); /* redraw callback */
void (*destroy) (xaccLedgerDisplay *); /* destroy callback */ void (*destroy) (xaccLedgerDisplay *); /* destroy callback */
gncUIWidget (*get_parent) (xaccLedgerDisplay *); /* get parent widget */ 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; Split *split;
int i, num_splits; int i, num_splits;
if (trans == NULL)
return;
xaccTransDisplayRefresh(trans); xaccTransDisplayRefresh(trans);
num_splits = xaccTransCountSplits(trans); num_splits = xaccTransCountSplits(trans);

View File

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

View File

@ -42,7 +42,7 @@ COMMON_SRCS := basiccell.c cellblock.c \
datecell.c pricecell.c QuickFill.c quickfillcell.c \ datecell.c pricecell.c QuickFill.c quickfillcell.c \
recncell.c splitreg.c \ recncell.c splitreg.c \
table-allgui.c table-html.c textcell.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 GNOME_SRCS := table-gnome.c
QT_SRCS := table-qt.cpp combocell-qt.cpp QT_SRCS := table-qt.cpp combocell-qt.cpp
CLEAN_SUBDIRS := gnome CLEAN_SUBDIRS := gnome

View File

@ -110,23 +110,72 @@ xaccGetQuickFill( QuickFill *qf, char c )
/********************************************************************\ /********************************************************************\
\********************************************************************/ \********************************************************************/
QuickFill * QuickFill *
xaccGetQuickFillStr( QuickFill *qf, const char *str ) xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len )
{ {
if (str == NULL) if (str == NULL)
return NULL; return NULL;
while (*str != '\0') while ((*str != '\0') && (len > 0))
{ {
if (qf == NULL) if (qf == NULL)
return NULL; return NULL;
qf = qf->qf[CHAR_TO_INDEX(*str)]; qf = qf->qf[CHAR_TO_INDEX(*str)];
str++; str++;
len--;
} }
return qf; 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 void

View File

@ -66,6 +66,8 @@ QuickFill *xaccMallocQuickFill( void );
void xaccFreeQuickFill( QuickFill *qf ); void xaccFreeQuickFill( QuickFill *qf );
QuickFill *xaccGetQuickFill( QuickFill *qf, char c ); QuickFill *xaccGetQuickFill( QuickFill *qf, char c );
QuickFill *xaccGetQuickFillStr( QuickFill *qf, const char *str ); 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 ); void xaccQFInsertText( QuickFill *qf, const char *text, QuickFillSort );
/** GLOBALS *********************************************************/ /** 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) void xaccInitBasicCell (BasicCell *cell)
{ {
cell->input_output = XACC_CELL_ALLOW_ALL; cell->input_output = XACC_CELL_ALLOW_ALL;
@ -50,15 +64,18 @@ void xaccInitBasicCell (BasicCell *cell)
cell->fg_color = 0x0; /* black */ cell->fg_color = 0x0; /* black */
cell->use_bg_color = 0; /* ignore the color */ cell->use_bg_color = 0; /* ignore the color */
cell->use_fg_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->changed = 0;
cell->set_value = NULL; cell->set_value = NULL;
cell->enter_cell = NULL; cell->enter_cell = NULL;
cell->modify_verify = NULL; cell->modify_verify = NULL;
cell->direct_update = NULL;
cell->leave_cell = NULL; cell->leave_cell = NULL;
cell->realize = NULL; cell->realize = NULL;
cell->move = NULL; cell->move = NULL;
cell->destroy = NULL; cell->destroy = NULL;
cell->get_help_value = BasicCellHelpValue;
cell->gui_private = NULL; cell->gui_private = NULL;
} }
@ -76,6 +93,10 @@ void xaccDestroyBasicCell (BasicCell *cell)
free (cell->value); free (cell->value);
} }
if (cell->blank_help) {
free (cell->blank_help);
}
/* help prevent access to freed memory */ /* help prevent access to freed memory */
xaccInitBasicCell (cell); 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 ====================== */ /* ================== end of file ====================== */

View File

@ -114,6 +114,14 @@
* It must return a string, or void if it rejects the change. * It must return a string, or void if it rejects the change.
* The returned string will be used to update the cell value. * 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: * Some memory management rules:
* (1) the callback must not modify the values of old, change, new * (1) the callback must not modify the values of old, change, new
* (2) if the callback likes the new string, it may return the * (2) if the callback likes the new string, it may return the
@ -177,6 +185,8 @@
#ifndef __XACC_BASIC_CELL_H__ #ifndef __XACC_BASIC_CELL_H__
#define __XACC_BASIC_CELL_H__ #define __XACC_BASIC_CELL_H__
#include "gnc-common.h"
/* define a bitmask */ /* define a bitmask */
#define XACC_CELL_ALLOW_NONE 0x0 #define XACC_CELL_ALLOW_NONE 0x0
#define XACC_CELL_ALLOW_SHADOW 0x1 #define XACC_CELL_ALLOW_SHADOW 0x1
@ -185,7 +195,6 @@
#define XACC_CELL_ALLOW_EXACT_ONLY 0x4 #define XACC_CELL_ALLOW_EXACT_ONLY 0x4
typedef struct _BasicCell BasicCell; typedef struct _BasicCell BasicCell;
typedef unsigned int uint32;
struct _BasicCell { struct _BasicCell {
@ -200,6 +209,7 @@ struct _BasicCell {
/* ==================================================== */ /* ==================================================== */
char * value; /* current value */ char * value; /* current value */
char *blank_help; /* help when value is blank */
unsigned int changed; /* 2^32-1 if value modified */ unsigned int changed; /* 2^32-1 if value modified */
char input_output; /* zero if output-only */ char input_output; /* zero if output-only */
@ -221,6 +231,13 @@ struct _BasicCell {
int *cursor_position, int *cursor_position,
int *start_selection, int *start_selection,
int *end_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 * (*leave_cell) (BasicCell *,
const char * current); const char * current);
@ -232,16 +249,20 @@ struct _BasicCell {
int phys_row, int phys_col); int phys_row, int phys_col);
void (* destroy) (BasicCell *); void (* destroy) (BasicCell *);
char * (*get_help_value) (BasicCell *);
/* general hook for gui-private data */ /* general hook for gui-private data */
void * gui_private; void * gui_private;
}; };
BasicCell * xaccMallocBasicCell (void); BasicCell * xaccMallocBasicCell (void);
void xaccInitBasicCell (BasicCell *); void xaccInitBasicCell (BasicCell *);
void xaccDestroyBasicCell (BasicCell *); void xaccDestroyBasicCell (BasicCell *);
void xaccSetBasicCellValue (BasicCell *, const char *); void xaccSetBasicCellValue (BasicCell *, const char *);
void xaccSetBasicCellBlankHelp (BasicCell *, const char *);
char * xaccBasicCellGetHelp (BasicCell *);
#endif /* __XACC_BASIC_CELL_H__ */ #endif /* __XACC_BASIC_CELL_H__ */
/* ------------------ end of file ---------------------- */ /* ------------------ end of file ---------------------- */

View File

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

View File

@ -88,10 +88,14 @@ struct _CellBlock {
* the currently active cursor). * the currently active cursor).
* *
* The passive_bg_color is the default color for the cell background * 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 active_bg_color;
uint32 passive_bg_color; uint32 passive_bg_color;
uint32 passive_bg_color2;
/* other attributes */ /* other attributes */
short *widths; /* column widths */ 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 =================== */ /* =============== end of file =================== */

View File

@ -44,7 +44,7 @@
typedef struct _ComboCell { typedef struct _ComboCell {
BasicCell cell; BasicCell cell;
char ** menuitems; /* not used in the gnome version */ char ** menuitems; /* not used in the gnome version */
} ComboCell; } ComboCell;
ComboCell * xaccMallocComboCell (void); ComboCell * xaccMallocComboCell (void);
@ -61,6 +61,21 @@ void xaccAddComboCellMenuItem (ComboCell *, char * menustr);
* to strict, i.e., only menu items are accepted. */ * to strict, i.e., only menu items are accepted. */
void xaccComboCellSetStrict (ComboCell *, gncBoolean); 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__ */ #endif /* __XACC_COMBO_CELL_H__ */
/* --------------- end of file ---------------------- */ /* --------------- end of file ---------------------- */

View File

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

View File

@ -42,7 +42,7 @@ LIBS = -L$(prefix)/lib @LIBS@ \
# See Makefile.common for information about these variables. # See Makefile.common for information about these variables.
GNOME_SRCS := gnucash-sheet.c gnucash-grid.c gnucash-color.c gnucash-cursor.c \ 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-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 default: gnome

View File

@ -31,6 +31,8 @@
own strings. own strings.
*/ */
#include "config.h"
#include <gnome.h> #include <gnome.h>
#include "splitreg.h" #include "splitreg.h"
@ -41,6 +43,7 @@
#include "gnucash-item-edit.h" #include "gnucash-item-edit.h"
#include "gnucash-item-list.h" #include "gnucash-item-list.h"
#include "global-options.h" #include "global-options.h"
#include "messages.h"
#include "util.h" #include "util.h"
@ -53,8 +56,10 @@ typedef struct _PopBox
GNCItemList *item_list; GNCItemList *item_list;
gint select_item_signal; gint select_item_signal;
gint change_item_signal;
gint key_press_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_in_sync; /* list in sync with menustrings? */
gboolean list_sorted; /* list has been sorted? */ gboolean list_sorted; /* list has been sorted? */
@ -64,13 +69,21 @@ typedef struct _PopBox
gboolean in_list_select; gboolean in_list_select;
gncBoolean strict; gncBoolean strict;
char complete_char; /* char to be used for auto-completion */
gchar *ignore_string;
gchar *ignore_help;
} PopBox; } 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 realizeCombo (BasicCell *bcell, void *w, int width);
static void moveCombo (BasicCell *bcell, int phys_row, int phys_col); static void moveCombo (BasicCell *bcell, int phys_row, int phys_col);
static void destroyCombo (BasicCell *bcell); 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 *cursor_position,
int *start_selection, int *start_selection,
int *end_selection); int *end_selection);
@ -101,13 +114,13 @@ void xaccInitComboCell (ComboCell *cell)
cell->cell.realize = realizeCombo; cell->cell.realize = realizeCombo;
cell->cell.destroy = destroyCombo; cell->cell.destroy = destroyCombo;
box = g_new(PopBox, 1); box = g_new0(PopBox, 1);
box->sheet = NULL; box->sheet = NULL;
box->item_edit = NULL; box->item_edit = NULL;
box->item_list = NULL; box->item_list = NULL;
box->menustrings = NULL; box->menustrings = NULL;
box->list_signals_connected = FALSE; box->signals_connected = FALSE;
box->list_in_sync = TRUE; box->list_in_sync = TRUE;
box->list_sorted = TRUE; box->list_sorted = TRUE;
box->list_popped = FALSE; box->list_popped = FALSE;
@ -118,6 +131,11 @@ void xaccInitComboCell (ComboCell *cell)
box->in_list_select = FALSE; box->in_list_select = FALSE;
box->strict = TRUE; 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; 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 static void
key_press_item_cb (GNCItemList *item_list, GdkEventKey *event, gpointer data) 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 static void
disconnect_list_signals (ComboCell *cell) combo_disconnect_signals (ComboCell *cell)
{ {
PopBox *box = (PopBox *) cell->cell.gui_private; PopBox *box = (PopBox *) cell->cell.gui_private;
if (!box->list_signals_connected) if (!box->signals_connected)
return; return;
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list))) 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), gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->select_item_signal); box->select_item_signal);
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->change_item_signal);
gtk_signal_disconnect(GTK_OBJECT(box->item_list), gtk_signal_disconnect(GTK_OBJECT(box->item_list),
box->key_press_signal); box->key_press_signal);
box->list_signals_connected = FALSE; box->signals_connected = FALSE;
} }
static void static void
connect_list_signals (ComboCell *cell) combo_connect_signals (ComboCell *cell)
{ {
PopBox *box = (PopBox *) cell->cell.gui_private; PopBox *box = (PopBox *) cell->cell.gui_private;
if (box->list_signals_connected) if (box->signals_connected)
return; return;
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list))) if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list)))
@ -190,13 +222,54 @@ connect_list_signals (ComboCell *cell)
GTK_SIGNAL_FUNC(select_item_cb), GTK_SIGNAL_FUNC(select_item_cb),
(gpointer) cell); (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 = box->key_press_signal =
gtk_signal_connect(GTK_OBJECT(box->item_list), gtk_signal_connect(GTK_OBJECT(box->item_list),
"key_press_event", "key_press_event",
GTK_SIGNAL_FUNC(key_press_item_cb), GTK_SIGNAL_FUNC(key_press_item_cb),
(gpointer) cell); (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 (cell->cell.realize == NULL)
{ {
if (box != NULL && box->item_list != NULL) { if (box != NULL && box->item_list != NULL) {
disconnect_list_signals(cell); combo_disconnect_signals(cell);
gtk_object_unref(GTK_OBJECT(box->item_list)); gtk_object_unref(GTK_OBJECT(box->item_list));
box->item_list = NULL; box->item_list = NULL;
} }
@ -241,6 +314,9 @@ void xaccDestroyComboCell (ComboCell *cell)
xaccFreeQuickFill(box->qf); xaccFreeQuickFill(box->qf);
box->qf = NULL; box->qf = NULL;
g_free(box->ignore_string);
g_free(box->ignore_help);
g_free(box); g_free(box);
cell->cell.gui_private = NULL; cell->cell.gui_private = NULL;
} }
@ -276,8 +352,14 @@ xaccClearComboCellMenu (ComboCell * cell)
box->qf = xaccMallocQuickFill(); box->qf = xaccMallocQuickFill();
if (box->item_list != NULL) if (box->item_list != NULL)
{
block_list_signals(cell);
gnc_item_list_clear(box->item_list); gnc_item_list_clear(box->item_list);
unblock_list_signals(cell);
}
box->list_in_sync = TRUE; box->list_in_sync = TRUE;
box->list_sorted = TRUE; box->list_sorted = TRUE;
} }
@ -329,7 +411,15 @@ xaccAddComboCellMenuItem (ComboCell *cell, char * menustr)
gnc_combo_sync_edit_list(box); gnc_combo_sync_edit_list(box);
if (box->item_list != NULL) if (box->item_list != NULL)
{
block_list_signals(cell);
gnc_item_list_append(box->item_list, menustr); 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 else
box->list_in_sync = FALSE; box->list_in_sync = FALSE;
@ -357,7 +447,7 @@ ComboMV (BasicCell *_cell,
int *start_selection, int *start_selection,
int *end_selection) int *end_selection)
{ {
QuickFillCell *cell = (QuickFillCell *) _cell; ComboCell *cell = (ComboCell *) _cell;
PopBox *box = cell->cell.gui_private; PopBox *box = cell->cell.gui_private;
const char *retval; const char *retval;
QuickFill *match; QuickFill *match;
@ -393,7 +483,11 @@ ComboMV (BasicCell *_cell,
if ((match == NULL) || (match->text == NULL)) if ((match == NULL) || (match->text == NULL))
{ {
xaccSetBasicCellValue (_cell, newval); xaccSetBasicCellValue (_cell, newval);
block_list_signals(cell);
gnc_item_list_select(box->item_list, NULL); gnc_item_list_select(box->item_list, NULL);
unblock_list_signals(cell);
return newval; return newval;
} }
@ -416,13 +510,9 @@ ComboMV (BasicCell *_cell,
box->list_popped = TRUE; box->list_popped = TRUE;
} }
gtk_signal_handler_block(GTK_OBJECT(box->item_list), block_list_signals(cell);
box->select_item_signal);
gnc_item_list_select(box->item_list, retval); gnc_item_list_select(box->item_list, retval);
unblock_list_signals(cell);
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
box->select_item_signal);
xaccSetBasicCellValue (_cell, retval); 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 static void
realizeCombo (BasicCell *bcell, void *data, int pixel_width) 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.leave_cell = leaveCombo;
cell->cell.destroy = destroyCombo; cell->cell.destroy = destroyCombo;
cell->cell.modify_verify = ComboMV; 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; 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), gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", FALSE, NULL); "is_combo", FALSE, NULL);
@ -476,13 +738,19 @@ moveCombo (BasicCell *bcell, int phys_row, int phys_col)
/* =============================================== */ /* =============================================== */
static const char * static const char *
enterCombo (BasicCell *bcell, const char *value, enterCombo (BasicCell *bcell,
const char *value,
int *cursor_position, int *cursor_position,
int *start_selection, int *start_selection,
int *end_selection) int *end_selection)
{ {
ComboCell *cell = (ComboCell *) bcell;
PopBox *box = (PopBox *) bcell->gui_private; 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_sync_edit_list(box);
gnc_combo_sort_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), gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", TRUE, NULL); "is_combo", TRUE, NULL);
block_list_signals(cell);
gnc_item_list_select(box->item_list, bcell->value); 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; *cursor_position = -1;
*start_selection = 0; *start_selection = 0;
@ -511,7 +781,7 @@ leaveCombo (BasicCell *bcell, const char *value)
PopBox *box = (PopBox *) bcell->gui_private; 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), gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
"is_combo", FALSE, NULL); "is_combo", FALSE, NULL);
@ -526,8 +796,10 @@ leaveCombo (BasicCell *bcell, const char *value)
(gpointer) value, (gpointer) value,
(GCompareFunc) safe_strcmp); (GCompareFunc) safe_strcmp);
/* hack, "Split" is ok, even though it's not in list */ /* The ignore string is ok, even if it's not in list. */
if (find == NULL && (safe_strcmp(value, "Split") != 0)) if (find == NULL &&
((box->ignore_string == NULL) ||
(safe_strcmp(value, box->ignore_string) != 0)))
return strdup(""); return strdup("");
} }
@ -549,6 +821,51 @@ xaccComboCellSetStrict (ComboCell *cell, gncBoolean strict)
box->strict = 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 =================== */ /* =============== 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); sheet_block = gnucash_sheet_get_block (grid->sheet, block, 0);
gdk_gc_set_foreground (grid->gc, sheet_block->bg_colors[i][j]); gdk_gc_set_foreground (grid->gc, sheet_block->bg_colors[i][j]);
gdk_draw_rectangle (drawable, grid->gc, TRUE, x, y, width, height); gdk_draw_rectangle (drawable, grid->gc, TRUE, x, y, width, height);
gdk_gc_set_foreground (grid->gc, &gn_black); gdk_gc_set_foreground (grid->gc, &gn_black);
/* draw the border */ /* draw the border */
gdk_draw_rectangle (drawable, grid->gc, FALSE, x, y, width, height); 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]; font = style->fonts[i][j];
else else
font = grid->normal_font; font = grid->normal_font;
gdk_gc_set_foreground (grid->gc, &gn_black);
gdk_gc_set_foreground (grid->gc, sheet_block->fg_colors[i][j]); gdk_gc_set_foreground (grid->gc, sheet_block->fg_colors[i][j]);
if (table->current_cursor_virt_row == block && if (table->current_cursor_virt_row == block &&
(!text || strlen(text) == 0)) { (!text || strlen(text) == 0)) {
font = grid->italic_font; font = grid->italic_font;

View File

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

View File

@ -28,7 +28,25 @@
#include "util.h" #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 GnomeCanvasItemClass *item_edit_parent_class;
static GdkAtom clipboard_atom = GDK_NONE;
static GdkAtom ctext_atom = GDK_NONE;
typedef struct _TextDrawInfo TextDrawInfo; typedef struct _TextDrawInfo TextDrawInfo;
struct _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, static void item_edit_show_combo_toggle (ItemEdit *item_edit,
gint x, gint y, gint x, gint y,
gint width, gint height, gint width, gint height,
@ -364,6 +373,10 @@ item_edit_init (ItemEdit *item_edit)
item_edit->editor = NULL; item_edit->editor = NULL;
item_edit->clipboard = 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 = NULL;
item_edit->combo_toggle.combo_button_item = NULL; item_edit->combo_toggle.combo_button_item = NULL;
item_edit->combo_toggle.toggle_offset = 0; 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); 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 static void
entry_changed (GtkEntry *entry, void *data) 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 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; GtkEditable *editable;
gint start_sel, end_sel; gint start_sel, end_sel;
@ -604,10 +659,14 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
if (start_sel == end_sel) if (start_sel == end_sel)
return; 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; item_edit->clipboard = clip;
if (!cut) if (!cut)
@ -620,53 +679,44 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
void 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 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 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(item_edit != NULL);
g_return_if_fail(IS_ITEM_EDIT(item_edit)); g_return_if_fail(IS_ITEM_EDIT(item_edit));
if ((item_edit->clipboard == NULL) || if (ctext_atom == GDK_NONE)
(item_edit->clipboard[0] == 0)) ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
return;
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) void
{ item_edit_paste_primary (ItemEdit *item_edit, guint32 time)
gtk_editable_delete_text(editable, start_sel, end_sel); {
current_pos = start_sel; g_return_if_fail(item_edit != NULL);
} g_return_if_fail(IS_ITEM_EDIT(item_edit));
clip = item_edit->clipboard; if (ctext_atom == GDK_NONE)
gtk_editable_insert_text(editable, clip, strlen(clip), &current_pos); ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
gtk_editable_select_region(editable, 0, 0); gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
gtk_editable_set_position(editable, current_pos); GDK_SELECTION_PRIMARY, ctext_atom, time);
} }
@ -871,6 +921,7 @@ item_edit_class_init (ItemEditClass *item_edit_class)
item_class->realize = item_edit_realize; item_class->realize = item_edit_realize;
} }
GtkType GtkType
item_edit_get_type (void) item_edit_get_type (void)
{ {
@ -921,6 +972,13 @@ create_combo_toggle(GnomeCanvasGroup *parent, ComboToggle *ct)
GnomeCanvasItem * GnomeCanvasItem *
item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry) 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; GnomeCanvasItem *item;
ItemEdit *item_edit; ItemEdit *item_edit;
@ -936,6 +994,17 @@ item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry)
create_combo_toggle(parent, &item_edit->combo_toggle); 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; 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); 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: Local Variables:
c-basic-offset: 8 c-basic-offset: 8

View File

@ -63,6 +63,7 @@ typedef struct
guint signal; /* the signal we connect */ guint signal; /* the signal we connect */
guint signal2; /* the other signal we connect */ guint signal2; /* the other signal we connect */
gboolean has_selection;
gboolean is_combo; gboolean is_combo;
gboolean show_list; gboolean show_list;
@ -101,9 +102,28 @@ gboolean item_edit_set_cursor_pos (ItemEdit *item_edit,
gboolean changed_cells, gboolean changed_cells,
gboolean extend_selection); gboolean extend_selection);
void item_edit_cut_clipboard (ItemEdit *item_edit); void item_edit_redraw (ItemEdit *item_edit);
void item_edit_copy_clipboard (ItemEdit *item_edit);
void item_edit_paste_clipboard (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 { typedef struct {
GnomeCanvasItemClass parent_class; GnomeCanvasItemClass parent_class;

View File

@ -28,6 +28,7 @@
enum enum
{ {
SELECT_ITEM, SELECT_ITEM,
CHANGE_ITEM,
KEY_PRESS_EVENT, KEY_PRESS_EVENT,
LAST_SIGNAL 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 static gboolean
gnc_item_list_key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) gnc_item_list_key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{ {
GNCItemList *item_list = GNC_ITEM_LIST(data); GNCItemList *item_list = GNC_ITEM_LIST(data);
GtkCList *clist;
gboolean got_text;
gchar *string;
gint row;
switch (event->keyval) { switch (event->keyval) {
case GDK_space: case GDK_Return:
if (event->state & GDK_CONTROL_MASK) clist = item_list->clist;
{ row = clist->focus_row;
event->state &= ~GDK_CONTROL_MASK; if (row < 0)
return FALSE; 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_Up:
case GDK_Page_Down: case GDK_Page_Down:
case GDK_Up: case GDK_Up:
@ -197,6 +243,16 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
GTK_TYPE_NONE, 1, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER); 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] = gnc_item_list_signals[KEY_PRESS_EVENT] =
gtk_signal_new ("key_press_event", gtk_signal_new ("key_press_event",
GTK_RUN_LAST, GTK_RUN_LAST,
@ -210,6 +266,10 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
gtk_object_class_add_signals(object_class, gtk_object_class_add_signals(object_class,
gnc_item_list_signals, gnc_item_list_signals,
LAST_SIGNAL); 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; gboolean got_text;
char *string; 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) if (!got_text)
return; return;
gtk_signal_emit(GTK_OBJECT(item_list), if (column < 0)
gnc_item_list_signals[SELECT_ITEM], string); 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); clist = gtk_clist_new(1);
gtk_box_pack_start(GTK_BOX(hbox), clist, TRUE, TRUE, 0); 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_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_BROWSE);
scrollbar = gtk_vscrollbar_new(NULL); scrollbar = gtk_vscrollbar_new(NULL);
gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0); 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_connect_after(GTK_OBJECT(hbox), "button_press_event",
GTK_SIGNAL_FUNC(gnc_item_list_button_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_connect(GTK_OBJECT(clist), "key_press_event",
GTK_SIGNAL_FUNC(gnc_item_list_key_event), GTK_SIGNAL_FUNC(gnc_item_list_key_event),

View File

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

View File

@ -36,8 +36,8 @@
#define DEFAULT_REGISTER_HEIGHT 400 #define DEFAULT_REGISTER_HEIGHT 400
#define DEFAULT_REGISTER_WIDTH 630 #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, static void gnucash_sheet_cell_set_from_table (GnucashSheet *sheet,
gint virt_row, gint virt_col, gint virt_row, gint virt_col,
@ -72,6 +72,12 @@ static GtkTableClass *register_parent_class;
static guint register_signals[LAST_SIGNAL]; static guint register_signals[LAST_SIGNAL];
void
gnucash_register_set_initial_rows(guint num_rows)
{
gnucash_register_initial_rows = num_rows;
}
gint gint
gnucash_sheet_cell_valid (GnucashSheet *sheet, gint virt_row, gint virt_col, gnucash_sheet_cell_valid (GnucashSheet *sheet, gint virt_row, gint virt_col,
gint cell_row, gint cell_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, table->current_cursor_virt_col,
cell_row, cell_row,
cell_col); 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 (sheet != NULL);
g_return_if_fail (GNUCASH_IS_SHEET(sheet)); g_return_if_fail (GNUCASH_IS_SHEET(sheet));
if ( vrow <= 0 || vrow > sheet->num_virt_rows || if ( vrow <= 0 || vrow > sheet->num_virt_rows ||
vcol < 0 || vcol > sheet->num_virt_cols) vcol < 0 || vcol > sheet->num_virt_cols)
return; return;
@ -796,18 +800,18 @@ compute_optimal_width (GnucashSheet *sheet)
{ {
SheetBlockStyle *style; SheetBlockStyle *style;
if (sheet->default_width >= 0)
return sheet->default_width;
if ((sheet == NULL) || (sheet->cursor_style == NULL)) if ((sheet == NULL) || (sheet->cursor_style == NULL))
return DEFAULT_REGISTER_WIDTH; return DEFAULT_REGISTER_WIDTH;
if (sheet->default_width >= 0)
return sheet->default_width;
style = sheet->cursor_style[GNUCASH_CURSOR_HEADER]; style = sheet->cursor_style[GNUCASH_CURSOR_HEADER];
if ((style == NULL) || (style->widths == NULL)) if ((style == NULL) || (style->widths == NULL))
return DEFAULT_REGISTER_WIDTH; 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; return sheet->default_width;
} }
@ -832,7 +836,7 @@ compute_optimal_height (GnucashSheet *sheet)
return DEFAULT_REGISTER_HEIGHT; return DEFAULT_REGISTER_HEIGHT;
row_height = style->dimensions->pixel_heights[0][0]; 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; return sheet->default_height;
} }
@ -1049,6 +1053,9 @@ gnucash_sheet_delete_cb (GtkWidget *widget,
int cursor_position = start_pos; int cursor_position = start_pos;
int start_sel, end_sel; int start_sel, end_sel;
if (end_pos <= start_pos)
return;
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor), gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
&p_row, &p_col); &p_row, &p_col);
gnucash_cursor_get_virt (GNUCASH_CURSOR (sheet->cursor), gnucash_cursor_get_virt (GNUCASH_CURSOR (sheet->cursor),
@ -1171,7 +1178,7 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
sheet->insert_signal = sheet->insert_signal =
gtk_signal_connect(GTK_OBJECT(sheet->entry), "insert_text", gtk_signal_connect(GTK_OBJECT(sheet->entry), "insert_text",
GTK_SIGNAL_FUNC(gnucash_sheet_insert_cb), GTK_SIGNAL_FUNC(gnucash_sheet_insert_cb),
sheet); sheet);
sheet->delete_signal = sheet->delete_signal =
gtk_signal_connect(GTK_OBJECT(sheet->entry), "delete_text", gtk_signal_connect(GTK_OBJECT(sheet->entry), "delete_text",
@ -1179,8 +1186,6 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
sheet); sheet);
} }
static gboolean dragging = FALSE;
static gboolean static gboolean
gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event) gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
{ {
@ -1194,14 +1199,20 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
sheet = GNUCASH_SHEET(widget); 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; return FALSE;
if (!(event->state & GDK_BUTTON1_MASK)) if (!(event->state & GDK_BUTTON1_MASK))
{
dragging = FALSE;
return FALSE; return FALSE;
}
gnome_canvas_get_scroll_offsets (GNOME_CANVAS(sheet), gnome_canvas_get_scroll_offsets (GNOME_CANVAS(sheet),
&xoffset, &yoffset); &xoffset, &yoffset);
@ -1221,14 +1232,28 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
static gboolean static gboolean
gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event) gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event)
{ {
GnucashSheet *sheet;
g_return_val_if_fail(widget != NULL, TRUE); g_return_val_if_fail(widget != NULL, TRUE);
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE); g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE);
g_return_val_if_fail(event != NULL, 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) if (event->button != 1)
return FALSE; 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; return TRUE;
} }
@ -1236,30 +1261,49 @@ gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event)
static void static void
gnucash_sheet_scroll_event(GnucashSheet *sheet, GdkEventButton *event) gnucash_sheet_scroll_event(GnucashSheet *sheet, GdkEventButton *event)
{ {
GtkAdjustment *vadj; GtkAdjustment *vadj;
gfloat multiplier = 1.0; gfloat multiplier = 1.0;
gfloat v_value; gfloat v_value;
vadj = sheet->vadj; vadj = sheet->vadj;
v_value = vadj->value; v_value = vadj->value;
if (event->state & GDK_SHIFT_MASK) if (event->state & GDK_SHIFT_MASK)
multiplier = 5.0; multiplier = 5.0;
switch (event->button) switch (event->button)
{ {
case 4: case 4:
v_value -= vadj->step_increment * multiplier; v_value -= vadj->step_increment * multiplier;
break; break;
case 5: case 5:
v_value += vadj->step_increment * multiplier; v_value += vadj->step_increment * multiplier;
break; break;
default: default:
return; 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 static gboolean
@ -1286,11 +1330,24 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
sheet = GNUCASH_SHEET (widget); sheet = GNUCASH_SHEET (widget);
table = sheet->table; 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) switch (event->button)
{ {
case 1: case 1:
break; break;
case 2: 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: case 3:
return FALSE; return FALSE;
case 4: 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_set_position(GTK_EDITABLE(sheet->entry), -1);
gtk_editable_select_region(GTK_EDITABLE(sheet->entry), 0, -1); gtk_editable_select_region(GTK_EDITABLE(sheet->entry), 0, -1);
item_edit_claim_selection (ITEM_EDIT(sheet->item_editor),
event->time);
return TRUE; return TRUE;
} }
if (event->type != GDK_BUTTON_PRESS) if (event->type != GDK_BUTTON_PRESS)
return FALSE; 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) && if ((new_p_row == current_p_row) && (new_p_col == current_p_col) &&
sheet->editing) sheet->editing)
@ -1359,11 +1422,18 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
GNC_TABLE_TRAVERSE_POINTER, GNC_TABLE_TRAVERSE_POINTER,
&new_p_row, &new_p_col); &new_p_row, &new_p_col);
gnucash_sheet_check_grab(sheet);
if (exit_register) if (exit_register)
return TRUE; return TRUE;
changed_cells = gnucash_sheet_cursor_move(sheet, new_p_row, new_p_col); 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), item_edit_set_cursor_pos (ITEM_EDIT(sheet->item_editor),
new_p_row, new_p_col, x, new_p_row, new_p_col, x,
changed_cells, FALSE); changed_cells, FALSE);
@ -1371,20 +1441,67 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
return TRUE; 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 static gboolean
gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event) gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
{ {
ItemEdit *item_edit; ItemEdit *item_edit;
gboolean handled = FALSE; gboolean handled = FALSE;
guint32 time;
item_edit = ITEM_EDIT(sheet->item_editor); item_edit = ITEM_EDIT(sheet->item_editor);
time = event->time;
switch (event->keyval) { switch (event->keyval) {
case GDK_C: case GDK_C:
case GDK_c: case GDK_c:
if (event->state & GDK_CONTROL_MASK) if (event->state & GDK_CONTROL_MASK)
{ {
item_edit_copy_clipboard(item_edit); item_edit_copy_clipboard(item_edit, time);
handled = TRUE; handled = TRUE;
} }
break; break;
@ -1392,7 +1509,7 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
case GDK_x: case GDK_x:
if (event->state & GDK_CONTROL_MASK) if (event->state & GDK_CONTROL_MASK)
{ {
item_edit_cut_clipboard(item_edit); item_edit_cut_clipboard(item_edit, time);
handled = TRUE; handled = TRUE;
} }
break; break;
@ -1400,19 +1517,19 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
case GDK_v: case GDK_v:
if (event->state & GDK_CONTROL_MASK) if (event->state & GDK_CONTROL_MASK)
{ {
item_edit_paste_clipboard(item_edit); item_edit_paste_clipboard(item_edit, time);
handled = TRUE; handled = TRUE;
} }
break; break;
case GDK_Insert: case GDK_Insert:
if (event->state & GDK_SHIFT_MASK) if (event->state & GDK_SHIFT_MASK)
{ {
item_edit_paste_clipboard(item_edit); item_edit_paste_clipboard(item_edit, time);
handled = TRUE; handled = TRUE;
} }
else if (event->state & GDK_CONTROL_MASK) else if (event->state & GDK_CONTROL_MASK)
{ {
item_edit_copy_clipboard(item_edit); item_edit_copy_clipboard(item_edit, time);
handled = TRUE; handled = TRUE;
} }
break; break;
@ -1421,6 +1538,97 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
return handled; 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 static gint
gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event) 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; table = sheet->table;
header = table->handlers[0][0]; header = table->handlers[0][0];
if (gnucash_sheet_direct_event(sheet, (GdkEvent *) event))
return TRUE;
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor), gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
&current_p_row, &current_p_col); &current_p_row, &current_p_col);
@ -1485,7 +1696,7 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
break; break;
case GDK_KP_Down: case GDK_KP_Down:
case GDK_Down: case GDK_Down:
if (event->state & GDK_CONTROL_MASK) if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
{ {
ItemEdit *item_edit; 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) gint virt_col, gint cell_row, gint cell_col)
{ {
SheetBlock *block; SheetBlock *block;
SheetBlockStyle *style;
Table *table; Table *table;
gint p_row, p_col; gint p_row, p_col;
gchar *text; gchar *text;
@ -1840,9 +2053,14 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
table = sheet->table; table = sheet->table;
block = gnucash_sheet_get_block (sheet, virt_row, virt_col); 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 if (cell_row >= 0 && cell_row <= style->nrows
&& cell_col >= 0 && cell_col <= block->style->ncols) { && cell_col >= 0 && cell_col <= style->ncols) {
if (block->entries[cell_row][cell_col]) if (block->entries[cell_row][cell_col])
g_free (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 static void
gnucash_sheet_block_destroy (GnucashSheet *sheet, gint virt_row, gint virt_col) gnucash_sheet_block_destroy (GnucashSheet *sheet, gint virt_row, gint virt_col)
{ {
@ -1954,7 +2221,7 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
Table *table; Table *table;
gint num_virt_rows; gint num_virt_rows;
gint i, j; gint i, j;
g_return_if_fail (sheet != NULL); g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUCASH_IS_SHEET(sheet)); g_return_if_fail (GNUCASH_IS_SHEET(sheet));
g_return_if_fail (sheet->table != NULL); g_return_if_fail (sheet->table != NULL);
@ -1968,7 +2235,7 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
gnucash_sheet_resize (sheet); gnucash_sheet_resize (sheet);
/* fill it up */ /* 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++) for (j = 0; j < table->num_virt_cols; j++)
gnucash_sheet_block_set_from_table (sheet, i, 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 static void
gnucash_sheet_class_init (GnucashSheetClass *class) gnucash_sheet_class_init (GnucashSheetClass *class)
{ {
@ -1999,12 +2313,18 @@ gnucash_sheet_class_init (GnucashSheetClass *class)
object_class->destroy = gnucash_sheet_destroy; object_class->destroy = gnucash_sheet_destroy;
widget_class->realize = gnucash_sheet_realize; widget_class->realize = gnucash_sheet_realize;
widget_class->size_request = gnucash_sheet_size_request; widget_class->size_request = gnucash_sheet_size_request;
widget_class->size_allocate = gnucash_sheet_size_allocate; widget_class->size_allocate = gnucash_sheet_size_allocate;
widget_class->key_press_event = gnucash_sheet_key_press_event; widget_class->key_press_event = gnucash_sheet_key_press_event;
widget_class->button_press_event = gnucash_button_press_event; widget_class->button_press_event = gnucash_button_press_event;
widget_class->button_release_event = gnucash_button_release_event; widget_class->button_release_event = gnucash_button_release_event;
widget_class->motion_notify_event = gnucash_motion_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->num_virt_cols = 0;
sheet->item_editor = NULL; sheet->item_editor = NULL;
sheet->entry = NULL; sheet->entry = NULL;
sheet->editing = FALSE; sheet->editing = FALSE;
sheet->button = 0;
sheet->grabbed = FALSE;
sheet->default_width = -1; sheet->default_width = -1;
sheet->default_height = -1; sheet->default_height = -1;
sheet->width = 0; sheet->width = 0;
@ -2098,7 +2420,7 @@ gnucash_sheet_new (Table *table)
GnomeCanvasGroup *sheet_group; GnomeCanvasGroup *sheet_group;
g_return_val_if_fail (table != NULL, NULL); g_return_val_if_fail (table != NULL, NULL);
sheet = gnucash_sheet_create (table); sheet = gnucash_sheet_create (table);
/* FIXME: */ /* FIXME: */
@ -2119,7 +2441,6 @@ gnucash_sheet_new (Table *table)
/* some register data */ /* some register data */
sheet->layout_info_hash_table = g_hash_table_new (g_str_hash, g_str_equal); 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); sheet->dimensions_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
/* The cursor */ /* The cursor */
sheet->cursor = gnucash_cursor_new (sheet_group); 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(GNUCASH_IS_REGISTER(reg));
g_return_if_fail(GTK_IS_WIDGET(popup)); g_return_if_fail(GTK_IS_WIDGET(popup));
g_return_if_fail(reg->sheet != NULL); 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->sheet, data);
gnome_popup_menu_attach(popup, reg->header_canvas, data);
} }
@ -2297,7 +2616,6 @@ gnucash_register_new (Table *table)
reg->hscrollbar = scrollbar; reg->hscrollbar = scrollbar;
gtk_widget_show(scrollbar); gtk_widget_show(scrollbar);
return widget; return widget;
} }

View File

@ -170,6 +170,9 @@ typedef struct {
gint editing; gint editing;
gint button; /* mouse button being held down */
gboolean grabbed; /* has the grab */
guint insert_signal; guint insert_signal;
guint delete_signal; guint delete_signal;
guint changed_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, SheetBlock *gnucash_sheet_get_block (GnucashSheet *sheet, gint vrow,
gint vcol); 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); 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, void gnucash_register_attach_popup(GnucashRegister *reg, GtkWidget *popup,
gpointer data); 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 { typedef struct {
GnomeCanvasClass parent_class; GnomeCanvasClass parent_class;

View File

@ -277,14 +277,14 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
case GNUCASH_CURSOR_SPLIT: case GNUCASH_CURSOR_SPLIT:
{ {
int i, j; 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] = CellLayoutData ld[1][8] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str}, {{{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 | 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}, {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"}, {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}, {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: case GNUCASH_CURSOR_DOUBLE:
{ {
int i, j; int i, j;
double perc[2][8] = {{0.10, 0.07, 0.15, 0.30, 0.02, 0.12, 0.12, 0.12}, 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.15, 0.68, 0.0, 0.0, 0.0, 0.0}}; {0.10, 0.07, 0.83, 0.0, 0.0, 0.0, 0.0, 0.0}};
CellLayoutData ld[2][8] = CellLayoutData ld[2][8] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str}, {{{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 | 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}, {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"}, {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}}, {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,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,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,2,0,7, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,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}, {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: case GNUCASH_CURSOR_SPLIT:
{ {
int i, j; 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] = CellLayoutData ld[1][11] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str}, {{{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 | 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}, {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"}, {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}, {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: case GNUCASH_CURSOR_DOUBLE:
{ {
int i, j; 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}}; {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] = CellLayoutData ld[2][11] =
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str}, {{{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 | 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}, {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"}, {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}, {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}}, {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,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,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,2,0,10, 0,0, NULL},
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,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}, {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); g_return_if_fail (font != NULL);
for (j = 0; j < layout_info->ncols; j++) { 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] = dimensions->pixel_heights[i][j] =
font->ascent + font->descent + font->ascent + font->descent +
2*CELL_VPADDING; 2*CELL_VPADDING;
@ -724,7 +724,7 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
if (layout_info->flags[i][j] & PIXELS_MIN) { if (layout_info->flags[i][j] & PIXELS_MIN) {
int allowed = dimensions->pixel_widths[i][j] int allowed = dimensions->pixel_widths[i][j]
- layout_info->pixels_min[i][j]; - layout_info->pixels_min[i][j];
adjustments[j] = MIN (allowed, cellspace); adjustments[j] = MAX(0, MIN (allowed, cellspace));
done[j] = (allowed < cellspace); done[j] = (allowed < cellspace);
} }
else adjustments[j] = cellspace; else adjustments[j] = cellspace;
@ -733,8 +733,8 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
else { else {
if (layout_info->flags[i][j] & PIXELS_MAX) { if (layout_info->flags[i][j] & PIXELS_MAX) {
int allowed = dimensions->pixel_widths[i][j] int allowed = dimensions->pixel_widths[i][j]
- layout_info->pixels_min[i][j]; - layout_info->pixels_max[i][j];
adjustments[j] = MAX (allowed, cellspace); adjustments[j] = MIN(0, MAX (allowed, cellspace));
done[j] = (allowed >cellspace); done[j] = (allowed >cellspace);
} }
else adjustments[j] = cellspace; else adjustments[j] = cellspace;
@ -772,7 +772,7 @@ set_dimensions_pass_four(GnucashSheet *sheet, CellLayoutInfo *layout_info,
int i = row, j; int i = row, j;
int c1, c2; int c1, c2;
int r; int r;
for (j = 0; j < layout_info->ncols; j++) { for (j = 0; j < layout_info->ncols; j++) {
if (!(layout_info->flags[i][j] & (LEFT_ALIGNED | RIGHT_ALIGNED | PIXELS_FIXED))) { 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; CellLayoutInfo *layout_info;
CellDimensions *dimensions; CellDimensions *dimensions;
gint width;
gint i;
layout_info = style->layout_info; layout_info = style->layout_info;
dimensions = style->dimensions; dimensions = style->dimensions;
set_dimensions_pass_one(sheet, layout_info, dimensions, 0); dimensions->height = 0;
set_dimensions_pass_two(sheet, layout_info, dimensions, 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 static void
compute_cell_origins_x (CellDimensions *dimensions, int row) 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 (GNUCASH_IS_SHEET (sheet));
g_return_if_fail (style != NULL); 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 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 * Set width of a specified cell and set the PIXEL_FIXED flag.
* same_size is TRUE, also set the width of any * If same_size is TRUE, also set the width of any
* SAME_SIZE cell which references this one. Otherwise those * SAME_SIZE cell which references this one. Otherwise those
* cells are set to PIXELS_FIXED with their current width. * 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 (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; 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; style->dimensions->pixel_widths[0][col] = width;
for (i = 0; i < style->nrows; i++) { for (i = 0; i < style->nrows; i++) {
@ -947,7 +978,12 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
if (same_size) if (same_size)
style->dimensions->pixel_widths[i][j] = width; style->dimensions->pixel_widths[i][j] = width;
else else
{
style->layout_info->flags[i][j] = PIXELS_FIXED; 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 void
gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style) gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
{ {
@ -991,14 +1025,16 @@ gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
style->layout_info->refcount--; style->layout_info->refcount--;
if (style->layout_info->refcount == 0) { 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_layout_info_destroy (style->layout_info);
} }
style->dimensions->refcount--; style->dimensions->refcount--;
if (style->dimensions->refcount == 0) { 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); 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 * SheetBlockStyle *
gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock, gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
gint cursor_type) gint cursor_type)
{ {
gint i, j;
SheetBlockStyle *style; SheetBlockStyle *style;
SplitRegister *sr; SplitRegister *sr;
gint i;
g_return_val_if_fail (sheet != NULL, NULL); g_return_val_if_fail (sheet != NULL, NULL);
g_return_val_if_fail (GNUCASH_IS_SHEET (sheet), 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->active_bg_color = g_new0 (GdkColor **, cellblock->numRows);
style->inactive_bg_color = g_new0 (GdkColor **, cellblock->numRows); style->inactive_bg_color = g_new0 (GdkColor **, cellblock->numRows);
style->labels = g_new0 (char **, cellblock->numRows); style->labels = g_new0 (char **, cellblock->numRows);
for ( i = 0; i < style->nrows; i++) { for ( i = 0; i < style->nrows; i++) {
style->widths[i] = g_new0(gint, style->ncols); style->widths[i] = g_new0(gint, style->ncols);
style->alignments[i] = g_new0 (GtkJustification, 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); style->labels[i] = g_new0 (char *, style->ncols);
} }
for (i = 0; i < style->nrows; i++) gnucash_sheet_style_recompile(style, cellblock, sr, cursor_type);
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_style_layout_init (sheet, style); gnucash_style_layout_init (sheet, style);
gnucash_style_dimensions_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_default_width(GnucashSheet *sheet, SheetBlockStyle *style);
gint gnucash_style_row_width(SheetBlockStyle *style, int row);
void gnucash_sheet_style_set_dimensions (GnucashSheet *sheet, void gnucash_sheet_style_set_dimensions (GnucashSheet *sheet,
SheetBlockStyle *style); SheetBlockStyle *style);
@ -43,6 +45,11 @@ SheetBlockStyle * gnucash_sheet_style_compile (GnucashSheet *sheet,
CellBlock *cellblock, CellBlock *cellblock,
gint cursor_type); 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, SheetBlockStyle *gnucash_sheet_get_style (GnucashSheet *sheet, gint vrow,
gint vcol); 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 void PriceSetValue (BasicCell *, const char *);
static char * xaccPriceCellPrintValue (PriceCell *cell); 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 */ /* hack alert -- the actual color should probably be configurable */
#define COLORIZE(cell,amt) { \ #define COLORIZE(cell,amt) { \
if (0.0 > amt) { \ if (0.0 > amt) { \
@ -79,7 +79,7 @@ PriceEnter (BasicCell *_cell,
static const char * static const char *
PriceMV (BasicCell *_cell, PriceMV (BasicCell *_cell,
const char * oldval, const char *oldval,
const char *change, const char *change,
const char *newval, const char *newval,
int *cursor_position, int *cursor_position,
@ -96,21 +96,28 @@ PriceMV (BasicCell *_cell,
decimal_point = lc->decimal_point[0]; decimal_point = lc->decimal_point[0];
/* accept the newval string if user action was delete, etc. */ /* accept the newval string if user action was delete, etc. */
if (change) { if (change != NULL)
/* if change is a decimal point, then count decimal points */ {
if (decimal_point == change[0]) { int i, count=0;
int i, count=0;
for (i=0; 0 != newval[i]; i++) { for (i=0; 0 != change[i]; i++)
if (decimal_point == newval[i]) count ++; {
} /* accept only numbers or a decimal point */
if (1 < count) return NULL; if (!isdigit(change[i]) && (decimal_point != change[i]))
} else { return NULL;
/* accept numeric, reject non-alpha edits */
if (! (isdigit (change[0]))) 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); cell->amount = xaccParseAmount (newval, cell->monetary);
SET ((&(cell->cell)), newval); SET ((&(cell->cell)), newval);
return newval; return newval;
@ -131,11 +138,34 @@ PriceLeave (BasicCell *_cell, const char *val)
return val; return val;
/* Otherwise, return the new one. */ /* Otherwise, return the new one. */
SET ((&(cell->cell)), newval);
return strdup(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 * PriceCell *
xaccMallocPriceCell (void) xaccMallocPriceCell (void)
{ {
@ -153,8 +183,9 @@ xaccInitPriceCell (PriceCell *cell)
xaccInitBasicCell( &(cell->cell)); xaccInitBasicCell( &(cell->cell));
cell->amount = 0.0; cell->amount = 0.0;
cell->blank_zero = 1; cell->precision = 2;
cell->prt_format = strdup ("%m"); cell->blank_zero = GNC_T;
cell->min_trail_zeros = 2;
cell->monetary = GNC_T; cell->monetary = GNC_T;
SET ( &(cell->cell), ""); SET ( &(cell->cell), "");
@ -164,6 +195,7 @@ xaccInitPriceCell (PriceCell *cell)
cell->cell.modify_verify = PriceMV; cell->cell.modify_verify = PriceMV;
cell->cell.leave_cell = PriceLeave; cell->cell.leave_cell = PriceLeave;
cell->cell.set_value = PriceSetValue; cell->cell.set_value = PriceSetValue;
cell->cell.get_help_value = PriceHelp;
} }
/* ================================================ */ /* ================================================ */
@ -172,7 +204,6 @@ void
xaccDestroyPriceCell (PriceCell *cell) xaccDestroyPriceCell (PriceCell *cell)
{ {
cell->amount = 0.0; cell->amount = 0.0;
free (cell->prt_format); cell->prt_format = 0x0;
xaccDestroyBasicCell ( &(cell->cell)); xaccDestroyBasicCell ( &(cell->cell));
} }
@ -182,34 +213,26 @@ static char *
xaccPriceCellPrintValue (PriceCell *cell) xaccPriceCellPrintValue (PriceCell *cell)
{ {
static char buff[PRTBUF]; static char buff[PRTBUF];
char tmpfmt[PRTBUF];
char tmpval[PRTBUF];
char *monet;
if (cell->blank_zero && DEQ(cell->amount, 0.0)) { if (cell->blank_zero && DEQ(cell->amount, 0.0)) {
strcpy(buff, ""); strcpy(buff, "");
return buff; return buff;
} }
/* check for monetary-style format not natively supported by printf */ xaccSPrintAmountGeneral(buff, cell->amount, PRTSEP, cell->precision,
/* hack alert -- this type of extended function should be abstracted cell->monetary, cell->min_trail_zeros);
* 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);
}
return buff; return buff;
} }
/* ================================================ */ /* ================================================ */
double
xaccGetPriceCellValue (PriceCell *cell)
{
assert(cell != NULL);
return cell->amount;
}
void xaccSetPriceCellValue (PriceCell * cell, double amt) 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); assert(cell != NULL);
cell->prt_format = strdup (fmt);
/* make sure that the cell is updated with the new format */ cell->precision = precision;
xaccSetPriceCellValue (cell, cell->amount);
} }
/* ================================================ */ /* ================================================ */
@ -240,11 +262,33 @@ void xaccSetPriceCellFormat (PriceCell * cell, char * fmt)
void void
xaccSetPriceCellMonetary (PriceCell * cell, gncBoolean monetary) xaccSetPriceCellMonetary (PriceCell * cell, gncBoolean monetary)
{ {
assert(cell != NULL);
cell->monetary = monetary; 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, void xaccSetDebCredCellValue (PriceCell * deb,
PriceCell * cred, double amt) PriceCell * cred, double amt)
{ {

View File

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

View File

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

View File

@ -43,6 +43,27 @@
/* This static indicates the debugging module that this .o belongs to. */ /* This static indicates the debugging module that this .o belongs to. */
static short module = MOD_REGISTER; 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 */ /* utility defines for cell configuration data */
#define DATE_CELL 0 #define DATE_CELL 0
#define NUM_CELL 1 #define NUM_CELL 1
@ -89,9 +110,9 @@ static short module = MOD_REGISTER;
#define DATE_CELL_ALIGN ALIGN_RIGHT #define DATE_CELL_ALIGN ALIGN_RIGHT
#define NUM_CELL_ALIGN ALIGN_LEFT #define NUM_CELL_ALIGN ALIGN_LEFT
#define ACTN_CELL_ALIGN ALIGN_LEFT #define ACTN_CELL_ALIGN ALIGN_LEFT
#define XFRM_CELL_ALIGN ALIGN_LEFT #define XFRM_CELL_ALIGN ALIGN_RIGHT
#define MXFRM_CELL_ALIGN ALIGN_LEFT #define MXFRM_CELL_ALIGN ALIGN_RIGHT
#define XTO_CELL_ALIGN ALIGN_LEFT #define XTO_CELL_ALIGN ALIGN_RIGHT
#define DESC_CELL_ALIGN ALIGN_LEFT #define DESC_CELL_ALIGN ALIGN_LEFT
#define MEMO_CELL_ALIGN ALIGN_LEFT #define MEMO_CELL_ALIGN ALIGN_LEFT
#define RECN_CELL_ALIGN ALIGN_CENTER #define RECN_CELL_ALIGN ALIGN_CENTER
@ -104,14 +125,7 @@ static short module = MOD_REGISTER;
#define SHRS_CELL_ALIGN ALIGN_RIGHT #define SHRS_CELL_ALIGN ALIGN_RIGHT
#define BALN_CELL_ALIGN ALIGN_RIGHT #define BALN_CELL_ALIGN ALIGN_RIGHT
/* Use 4 decimal places for everything that isn't a $ value #define SHARES_PRECISION 4
* 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"
/* ============================================== */ /* ============================================== */
@ -357,27 +371,29 @@ configLayout (SplitRegister *reg)
curs = reg->double_cursor; curs = reg->double_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 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); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0); FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0); FANCY (CRED, credit, 6, 0);
FANCY (BALN, balance, 7, 0); FANCY (BALN, balance, 7, 0);
FANCY (ACTN, action, 1, 1); FANCY (ACTN, action, 1, 1);
FANCY (MXFRM, mxfrm, 2, 1); FANCY (MEMO, memo, 2, 1);
BASIC (MEMO, memo, 3, 1);
curs = reg->trans_cursor; curs = reg->trans_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0); BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0); FANCY (DESC, desc, 2, 0);
BASIC (RECN, recn, 4, 0); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0);
FANCY (BALN, balance, 7, 0); FANCY (BALN, balance, 7, 0);
curs = reg->split_cursor; curs = reg->split_cursor;
FANCY (ACTN, action, 1, 0); FANCY (ACTN, action, 1, 0);
FANCY (XFRM, xfrm, 2, 0); FANCY (MEMO, memo, 2, 0);
BASIC (MEMO, memo, 3, 0); FANCY (XFRM, xfrm, 3, 0);
FANCY (NDEBT, ndebit, 5, 0); FANCY (NDEBT, ndebit, 5, 0);
FANCY (NCRED, ncredit, 6, 0); FANCY (NCRED, ncredit, 6, 0);
@ -385,8 +401,8 @@ configLayout (SplitRegister *reg)
curs = reg->single_cursor; curs = reg->single_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0); BASIC (NUM, num, 1, 0);
FANCY (MXFRM, mxfrm, 2, 0); FANCY (DESC, desc, 2, 0);
FANCY (DESC, desc, 3, 0); FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0); FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0); FANCY (CRED, credit, 6, 0);
@ -404,7 +420,8 @@ configLayout (SplitRegister *reg)
curs = reg->double_cursor; curs = reg->double_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 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); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0); FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0); FANCY (CRED, credit, 6, 0);
@ -414,14 +431,13 @@ configLayout (SplitRegister *reg)
FANCY (BALN, balance, 10, 0); FANCY (BALN, balance, 10, 0);
FANCY (ACTN, action, 1, 1); FANCY (ACTN, action, 1, 1);
FANCY (MXFRM, mxfrm, 2, 1); FANCY (MEMO, memo, 2, 1);
BASIC (MEMO, memo, 3, 1);
/* only the transaction cursor gets used */ /* only the transaction cursor gets used */
curs = reg->trans_cursor; curs = reg->trans_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0); BASIC (NUM, num, 1, 0);
FANCY (DESC, desc, 3, 0); FANCY (DESC, desc, 2, 0);
BASIC (RECN, recn, 4, 0); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0); FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0); FANCY (CRED, credit, 6, 0);
@ -432,8 +448,8 @@ configLayout (SplitRegister *reg)
curs = reg->split_cursor; curs = reg->split_cursor;
FANCY (ACTN, action, 1, 0); FANCY (ACTN, action, 1, 0);
FANCY (XFRM, xfrm, 2, 0); FANCY (MEMO, memo, 2, 0);
BASIC (MEMO, memo, 3, 0); FANCY (XFRM, xfrm, 3, 0);
FANCY (NDEBT, ndebit, 5, 0); FANCY (NDEBT, ndebit, 5, 0);
FANCY (NCRED, ncredit, 6, 0); FANCY (NCRED, ncredit, 6, 0);
@ -441,8 +457,8 @@ configLayout (SplitRegister *reg)
curs = reg->single_cursor; curs = reg->single_cursor;
FANCY (DATE, date, 0, 0); FANCY (DATE, date, 0, 0);
BASIC (NUM, num, 1, 0); BASIC (NUM, num, 1, 0);
FANCY (MXFRM, mxfrm, 2, 0); FANCY (DESC, desc, 2, 0);
FANCY (DESC, desc, 3, 0); FANCY (MXFRM, mxfrm, 3, 0);
BASIC (RECN, recn, 4, 0); BASIC (RECN, recn, 4, 0);
FANCY (DEBT, debit, 5, 0); FANCY (DEBT, debit, 5, 0);
FANCY (CRED, credit, 6, 0); FANCY (CRED, credit, 6, 0);
@ -700,7 +716,8 @@ configTraverse (SplitRegister *reg)
/* ============================================== */ /* ============================================== */
SplitRegister * xaccMallocSplitRegister (int type) SplitRegister *
xaccMallocSplitRegister (int type)
{ {
SplitRegister * reg; SplitRegister * reg;
reg = (SplitRegister *) malloc (sizeof (SplitRegister)); 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 static void
configCursors (SplitRegister *reg) configCursors (SplitRegister *reg)
{ {
/* --------------------------- */ xaccSplitRegisterConfigColors(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 */
} }
/* ============================================== */ /* ============================================== */
@ -808,6 +869,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
CellBlock *header; CellBlock *header;
int phys_r, phys_c; int phys_r, phys_c;
reg->table = NULL;
reg->user_data = NULL; reg->user_data = NULL;
reg->destroy = NULL; reg->destroy = NULL;
reg->type = type; reg->type = type;
@ -835,7 +897,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
HDR (VALU); HDR (VALU);
HDR (SHRS); HDR (SHRS);
HDR (BALN); HDR (BALN);
HDR (NCRED); HDR (NCRED);
HDR (NDEBT); HDR (NDEBT);
@ -854,7 +916,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
NEW (mxfrm, Combo); NEW (mxfrm, Combo);
NEW (xto, Combo); NEW (xto, Combo);
NEW (action, Combo); NEW (action, Combo);
NEW (memo, Text); NEW (memo, QuickFill);
NEW (credit, Price); NEW (credit, Price);
NEW (debit, Price); NEW (debit, Price);
NEW (price, Price); NEW (price, Price);
@ -885,9 +947,24 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
* cells handles this for us. * cells handles this for us.
*/ */
reg -> nullCell -> input_output = XACC_CELL_ALLOW_NONE; reg->nullCell->input_output = XACC_CELL_ALLOW_NONE;
xaccSetBasicCellValue (reg->nullCell, ""); 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. */ /* balance cell does not accept input; its display only. */
/* however, we *do* want it to shadow the true cell contents when /* however, we *do* want it to shadow the true cell contents when
* the cursor is repositioned. Othewise, it will just display * 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; reg->recnCell->input_output |= XACC_CELL_ALLOW_EXACT_ONLY;
/* the debit/credit/value cells show blank if value is 0.00 */ /* Initialize price cells */
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.
*/
xaccSetPriceCellValue (reg->debitCell, 0.0); xaccSetPriceCellValue (reg->debitCell, 0.0);
xaccSetPriceCellValue (reg->creditCell, 0.0); xaccSetPriceCellValue (reg->creditCell, 0.0);
xaccSetPriceCellValue (reg->valueCell, 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 /* The format for share-related info is a printf-style
* format string for a double. */ * format string for a double. */
xaccSetPriceCellFormat (reg->shrsCell, SHRS_CELL_FORMAT); xaccSetPriceCellMinTrailZeros (reg->shrsCell, 0);
xaccSetPriceCellMonetary (reg->shrsCell, GNC_F); xaccSetPriceCellPrecision (reg->shrsCell, SHARES_PRECISION);
/* The action cell should accept strings not in the list */ /* The action cell should accept strings not in the list */
xaccComboCellSetStrict (reg->actionCell, GNC_F); xaccComboCellSetStrict (reg->actionCell, GNC_F);
xaccSetBasicCellBlankHelp (&reg->actionCell->cell, ACTION_CELL_HELP);
/* number format for share quantities in stock ledgers */ /* number format for share quantities in stock ledgers */
switch (type & REG_TYPE_MASK) { switch (type & REG_TYPE_MASK) {
case STOCK_REGISTER: case STOCK_REGISTER:
case PORTFOLIO: case PORTFOLIO:
case CURRENCY_REGISTER: case CURRENCY_REGISTER:
xaccSetPriceCellFormat (reg->debitCell, DEBIT_CELL_FORMAT); xaccSetPriceCellMinTrailZeros (reg->debitCell, 0);
xaccSetPriceCellFormat (reg->creditCell, CREDIT_CELL_FORMAT); xaccSetPriceCellMinTrailZeros (reg->creditCell, 0);
xaccSetPriceCellFormat (reg->ndebitCell, DEBIT_CELL_FORMAT); xaccSetPriceCellMinTrailZeros (reg->ndebitCell, 0);
xaccSetPriceCellFormat (reg->ncreditCell, CREDIT_CELL_FORMAT); xaccSetPriceCellMinTrailZeros (reg->ncreditCell, 0);
xaccSetPriceCellFormat (reg->priceCell, DEBIT_CELL_FORMAT);
xaccSetPriceCellMonetary (reg->debitCell, GNC_F); xaccSetPriceCellPrecision (reg->debitCell, SHARES_PRECISION);
xaccSetPriceCellMonetary (reg->creditCell, GNC_F); xaccSetPriceCellPrecision (reg->creditCell, SHARES_PRECISION);
xaccSetPriceCellMonetary (reg->ndebitCell, GNC_F); xaccSetPriceCellPrecision (reg->ndebitCell, SHARES_PRECISION);
xaccSetPriceCellMonetary (reg->ncreditCell, GNC_F); xaccSetPriceCellPrecision (reg->ncreditCell, SHARES_PRECISION);
xaccSetPriceCellMonetary (reg->priceCell, GNC_F); xaccSetPriceCellPrecision (reg->priceCell, SHARES_PRECISION);
xaccSetBasicCellBlankHelp (&reg->priceCell->cell, PRICE_CELL_HELP);
xaccSetBasicCellBlankHelp (&reg->valueCell->cell, VALUE_CELL_HELP);
break; break;
default: default:
break; break;
@ -958,6 +1029,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
/* -------------------------------- */ /* -------------------------------- */
phys_r = header->numRows; phys_r = header->numRows;
reg->cursor_phys_col = 0;
reg->cursor_phys_row = phys_r; /* cursor on first line past header */ reg->cursor_phys_row = phys_r; /* cursor on first line past header */
reg->cursor_virt_row = 1; reg->cursor_virt_row = 1;
@ -986,6 +1058,8 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
xaccMoveCursor (table, header->numRows, 0); xaccMoveCursor (table, header->numRows, 0);
reg->table = table; reg->table = table;
configTable(reg);
} }
/* ============================================== */ /* ============================================== */
@ -997,12 +1071,14 @@ xaccConfigSplitRegister (SplitRegister *reg, int newtype)
reg->type = 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. */ * are properly initialized. */
xaccCreateCursor (reg->table, reg->single_cursor); xaccCreateCursor (reg->table, reg->single_cursor);
xaccCreateCursor (reg->table, reg->double_cursor); xaccCreateCursor (reg->table, reg->double_cursor);
xaccCreateCursor (reg->table, reg->trans_cursor); xaccCreateCursor (reg->table, reg->trans_cursor);
xaccCreateCursor (reg->table, reg->split_cursor); xaccCreateCursor (reg->table, reg->split_cursor);
configTable(reg);
} }
/* ============================================== */ /* ============================================== */
@ -1042,7 +1118,7 @@ xaccDestroySplitRegister (SplitRegister *reg)
xaccDestroyComboCell (reg->xfrmCell); xaccDestroyComboCell (reg->xfrmCell);
xaccDestroyComboCell (reg->mxfrmCell); xaccDestroyComboCell (reg->mxfrmCell);
xaccDestroyComboCell (reg->xtoCell); xaccDestroyComboCell (reg->xtoCell);
xaccDestroyBasicCell (reg->memoCell); xaccDestroyQuickFillCell (reg->memoCell);
xaccDestroyPriceCell (reg->creditCell); xaccDestroyPriceCell (reg->creditCell);
xaccDestroyPriceCell (reg->debitCell); xaccDestroyPriceCell (reg->debitCell);
xaccDestroyPriceCell (reg->priceCell); xaccDestroyPriceCell (reg->priceCell);
@ -1093,7 +1169,7 @@ xaccSplitRegisterGetChangeFlag (SplitRegister *reg)
changed |= MOD_XFRM & reg->xfrmCell->cell.changed; changed |= MOD_XFRM & reg->xfrmCell->cell.changed;
changed |= MOD_MXFRM & reg->mxfrmCell->cell.changed; changed |= MOD_MXFRM & reg->mxfrmCell->cell.changed;
changed |= MOD_XTO & reg->xtoCell->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->creditCell->cell.changed;
changed |= MOD_AMNT & reg->debitCell->cell.changed; changed |= MOD_AMNT & reg->debitCell->cell.changed;
changed |= MOD_PRIC & reg->priceCell->cell.changed; changed |= MOD_PRIC & reg->priceCell->cell.changed;
@ -1119,7 +1195,7 @@ xaccSplitRegisterClearChangeFlag (SplitRegister *reg)
reg->xfrmCell->cell.changed = 0; reg->xfrmCell->cell.changed = 0;
reg->mxfrmCell->cell.changed = 0; reg->mxfrmCell->cell.changed = 0;
reg->xtoCell->cell.changed = 0; reg->xtoCell->cell.changed = 0;
reg->memoCell->changed = 0; reg->memoCell->cell.changed = 0;
reg->creditCell->cell.changed = 0; reg->creditCell->cell.changed = 0;
reg->debitCell->cell.changed = 0; reg->debitCell->cell.changed = 0;
reg->priceCell->cell.changed = 0; reg->priceCell->cell.changed = 0;

View File

@ -143,7 +143,7 @@ struct _SplitRegister {
ComboCell * xfrmCell; ComboCell * xfrmCell;
ComboCell * mxfrmCell; ComboCell * mxfrmCell;
ComboCell * xtoCell; ComboCell * xtoCell;
BasicCell * memoCell; QuickFillCell * memoCell;
PriceCell * creditCell; PriceCell * creditCell;
PriceCell * debitCell; PriceCell * debitCell;
PriceCell * priceCell; PriceCell * priceCell;
@ -177,14 +177,41 @@ struct _SplitRegister {
/* The destroy callback gives user's a chance /* The destroy callback gives user's a chance
* to free up any associated user_hook data */ * to free up any associated user_hook data */
void (* destroy) (SplitRegister *); 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); SplitRegister * xaccMallocSplitRegister (int type);
void xaccInitSplitRegister (SplitRegister *, int type); void xaccInitSplitRegister (SplitRegister *, int type);
void xaccConfigSplitRegister (SplitRegister *, int type); void xaccConfigSplitRegister (SplitRegister *, int type);
void xaccDestroySplitRegister (SplitRegister *); void xaccDestroySplitRegister (SplitRegister *);
void xaccSetSplitRegisterColors (SplitRegisterColors reg_colors);
void xaccSplitRegisterConfigColors (SplitRegister *reg);
/* returns non-zero value if updates have been made to data */ /* returns non-zero value if updates have been made to data */
unsigned int xaccSplitRegisterGetChangeFlag (SplitRegister *); unsigned int xaccSplitRegisterGetChangeFlag (SplitRegister *);

View File

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

View File

@ -154,6 +154,10 @@ struct _RevLocator {
typedef struct _RevLocator 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 /* The number of "physical" rows/cols is the number
* of displayed one-line gui rows/cols in the table. * of displayed one-line gui rows/cols in the table.
@ -202,6 +206,8 @@ struct _Table {
int *p_new_phys_col, int *p_new_phys_col,
void *client_data); void *client_data);
TableSetHelpFunc set_help;
void * client_data; void * client_data;
/* string values for each cell, /* string values for each cell,
@ -214,6 +220,12 @@ struct _Table {
uint32 **bg_colors; uint32 **bg_colors;
uint32 **fg_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, /* handler locators for each cell,
* of dimension num_phys_rows * num_phys_cols */ * of dimension num_phys_rows * num_phys_cols */
Locator ***locators; Locator ***locators;
@ -363,17 +375,20 @@ xaccRefreshCursorGUI (Table * table, gncBoolean do_scroll);
* However, don't just change it, because it will break functional code. * However, don't just change it, because it will break functional code.
*/ */
const char * 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 *cursor_position,
int *start_selection, int *start_selection,
int *end_selection); int *end_selection);
const char * 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* old_text);
const char * 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 *oldval,
const char *change, const char *change,
char *newval, char *newval,
@ -382,7 +397,18 @@ gnc_table_modify_update(Table *table, int row, int col,
int *end_selection); int *end_selection);
gncBoolean 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, gncTableTraversalDir dir,
int *dest_row, int *dest_row,
int *dest_col); int *dest_col);

View File

@ -60,7 +60,7 @@ xaccCreateTable (GtkWidget *widget, void *data)
GnucashSheet *sheet; GnucashSheet *sheet;
GnucashRegister *greg; GnucashRegister *greg;
Table *table; Table *table;
g_return_if_fail (widget != NULL); g_return_if_fail (widget != NULL);
g_return_if_fail (GNUCASH_IS_REGISTER (widget)); g_return_if_fail (GNUCASH_IS_REGISTER (widget));
g_return_if_fail (data != NULL); g_return_if_fail (data != NULL);
@ -76,7 +76,7 @@ xaccCreateTable (GtkWidget *widget, void *data)
gtk_widget_ref (table->table_widget); gtk_widget_ref (table->table_widget);
/* config the cell-block styles */ /* config the cell-block styles */
sheet->cursor_style[GNUCASH_CURSOR_HEADER] = sheet->cursor_style[GNUCASH_CURSOR_HEADER] =
gnucash_sheet_style_compile (sheet, gnucash_sheet_style_compile (sheet,
sr->header, sr->header,
@ -107,8 +107,6 @@ xaccCreateTable (GtkWidget *widget, void *data)
gnucash_sheet_table_load (sheet); gnucash_sheet_table_load (sheet);
gnucash_sheet_cursor_set_from_table (sheet, TRUE); gnucash_sheet_cursor_set_from_table (sheet, TRUE);
gnucash_sheet_redraw_all (sheet); gnucash_sheet_redraw_all (sheet);
return;
} }
@ -116,6 +114,8 @@ void
xaccRefreshTableGUI (Table * table) xaccRefreshTableGUI (Table * table)
{ {
GnucashSheet *sheet; GnucashSheet *sheet;
SheetBlockStyle *style;
SplitRegister *sr;
if (!table) if (!table)
return; return;
@ -123,8 +123,29 @@ xaccRefreshTableGUI (Table * table)
return; return;
g_return_if_fail (GNUCASH_IS_SHEET (table->table_widget)); g_return_if_fail (GNUCASH_IS_SHEET (table->table_widget));
sheet = GNUCASH_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); gnucash_sheet_table_load (sheet);

View File

@ -7,6 +7,20 @@
;; (use-modules (gnc)) ;; (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. ;; Test for slib.
(let* ((try-slib (lambda () (use-modules (ice-9 slib)))) (let* ((try-slib (lambda () (use-modules (ice-9 slib))))
(handler (lambda args #f)) (handler (lambda args #f))
@ -14,27 +28,22 @@
(if (not result) (if (not result)
(begin (begin
(newline) (newline)
(display "It appears you do not have the 'slib' scheme\n") (display "It appears you do not have the 'slib' scheme ")
(display "library installed. You need slib2c6 or later\n") (display "library installed.\nYou need slib2c4 or later ")
(display "to run GnuCash.\n") (display "to run GnuCash.\n")
(newline) (newline)
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n") (display-slib-error)
(newline)
(exit 1)))) (exit 1))))
;; This variable determines whether slib-backup.scm gets loaded.
(define gnc:*load-slib-backup* #f)
;; Test for slib >= 2c6. ;; Test for slib >= 2c6.
(let* ((try-slib (lambda () (require 'printf) (sprintf #f "test"))) (let* ((try-slib (lambda () (require 'printf) (sprintf #f "test")))
(handler (lambda args #f)) (handler (lambda args #f))
(result (catch #t try-slib handler))) (result (catch #t try-slib handler)))
(if (not result) (if (not result)
(begin (set! gnc:*load-slib-backup* #t)))
(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))))
(define (build-path firstelement . restofpath) (define (build-path firstelement . restofpath)

View File

@ -1,4 +1,3 @@
(use-modules (ice-9 slib))
(require 'hash-table) (require 'hash-table)
(define gnc:register-c-side-scheme-ptr #f) (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:register-c-side-scheme-ptr register-c-side-scheme-ptr)
(set! gnc:unregister-c-side-scheme-ptr-id unregister-c-side-scheme-ptr-id)) (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") (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) (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)" (define menu (gnc:make-menu "Extensions" (list "_Settings")))
"Import QIF File - Scripted in Guile."
(lambda ()
(gnc:extensions-qif-import win))))
(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) (define (gnc:startup)
(gnc:debug "starting up.") (gnc:debug "starting up.")
(if (not (gnc:handle-command-line-args)) (if (not (gnc:handle-command-line-args))
@ -14,10 +13,9 @@
;; Now we can load a bunch of files. ;; Now we can load a bunch of files.
(gnc:depend "doc.scm") (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 "text-export.scm")
(gnc:depend "importqif.scm") (gnc:depend "importqif.scm")
(gnc:depend "test.scm")
(gnc:depend "report.scm") (gnc:depend "report.scm")
;; FIXME: These do not belong here, but for now, we're putting them ;; 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 ;; Just load these since we might want to redefine them on the fly
;; and we're going to change this mechanism anyway... ;; and we're going to change this mechanism anyway...
(gnc:load "report/hello-world.scm") (let
(gnc:load "report/balance-and-pnl.scm") ((repdir
(gnc:load "report/transaction-report.scm") (opendir (string-append gnc:_share-dir-default_ "/scm/report"))))
(gnc:load "report/average-balance.scm") (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 ;; Load the system configs
(if (not (gnc:load-system-config-if-needed)) (if (not (gnc:load-system-config-if-needed))
@ -67,8 +73,8 @@
(gnc:ui-shutdown)))) (gnc:ui-shutdown))))
(else (else
(gnc:hook-run-danglers gnc:*shutdown-hook*)
(gnc:ui-destroy) (gnc:ui-destroy)
(gnc:hook-run-danglers gnc:*shutdown-hook*)
(exit exit-status)))) (exit exit-status))))
(define (gnc:ui-finish) (define (gnc:ui-finish)

View File

@ -69,6 +69,10 @@
(let ((getter (gnc:option-getter option))) (let ((getter (gnc:option-getter option)))
(getter))) (getter)))
(define (gnc:option-default-value option)
(let ((getter (gnc:option-default-getter option)))
(getter)))
(define (gnc:restore-form-generator value->string) (define (gnc:restore-form-generator value->string)
(lambda () (string-append (lambda () (string-append
"(lambda (option) " "(lambda (option) "
@ -76,6 +80,10 @@
(value->string) (value->string)
")))"))) ")))")))
(define (gnc:value->string value)
(call-with-output-string
(lambda (port) (write value port))))
(define (gnc:make-string-option (define (gnc:make-string-option
section section
name name
@ -83,7 +91,7 @@
documentation-string documentation-string
default-value) default-value)
(let* ((value default-value) (let* ((value default-value)
(value->string (lambda () (string-append "\"" value "\"")))) (value->string (lambda () (gnc:value->string value))))
(gnc:make-option (gnc:make-option
section name sort-tag 'string documentation-string section name sort-tag 'string documentation-string
(lambda () value) (lambda () value)
@ -102,7 +110,7 @@
documentation-string documentation-string
default-value) default-value)
(let* ((value default-value) (let* ((value default-value)
(value->string (lambda () (if value "#t" "#f")))) (value->string (lambda () (gnc:value->string value))))
(gnc:make-option (gnc:make-option
section name sort-tag 'boolean documentation-string section name sort-tag 'boolean documentation-string
(lambda () value) (lambda () value)
@ -129,10 +137,8 @@
(and (pair? date) (exact? (car date)) (exact? (cdr date)))) (and (pair? date) (exact? (car date)) (exact? (cdr date))))
(let* ((value (default-getter)) (let* ((value (default-getter))
(value->string (value->string (lambda ()
(lambda () (string-append "'" (gnc:value->string value)))))
(string-append "(" (number->string (car value))
" . " (number->string (cdr value)) ")"))))
(gnc:make-option (gnc:make-option
section name sort-tag 'date documentation-string section name sort-tag 'date documentation-string
(lambda () value) (lambda () value)
@ -200,7 +206,7 @@
(let* ((value default-value) (let* ((value default-value)
(value->string (lambda () (value->string (lambda ()
(string-append "'" (symbol->string value))))) (string-append "'" (gnc:value->string value)))))
(gnc:make-option (gnc:make-option
section name sort-tag 'multichoice documentation-string section name sort-tag 'multichoice documentation-string
(lambda () value) (lambda () value)
@ -216,6 +222,100 @@
(list #f "multichoice-option: illegal choice"))) (list #f "multichoice-option: illegal choice")))
ok-values))) 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 ;; Create a new options database
(define (gnc:new-options) (define (gnc:new-options)
@ -279,7 +379,8 @@
section-hash)) section-hash))
(hash-for-each (hash-for-each
(lambda (section hash) (lambda (section hash)
(section-thunk section hash) (if section-thunk
(section-thunk section hash))
(if option-thunk (if option-thunk
(section-for-each hash option-thunk))) (section-for-each hash option-thunk)))
option-hash)) option-hash))
@ -302,16 +403,18 @@
(string-append "\n; Section: " section "\n\n") (string-append "\n; Section: " section "\n\n")
port)) port))
(lambda (option) (lambda (option)
(let* ((generator (gnc:option-generate-restore-form option)) (let ((value (gnc:option-value option))
(restore-code (false-if-exception (generator)))) (default-value (gnc:option-default-value option)))
(if restore-code (if
(display (not (equal? value default-value))
(generate-option-restore-form option restore-code) (let* ((generator (gnc:option-generate-restore-form option))
port)))))) (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") (call-with-output-string generate-forms))
(forms (call-with-output-string generate-forms)))
(string-append header forms)))
(define (register-callback section name callback) (define (register-callback section name callback)
(let ((id last-callback-id) (let ((id last-callback-id)
@ -344,16 +447,17 @@
(clear-changes)) (clear-changes))
(define (dispatch key) (define (dispatch key)
(cond ((eq? key 'lookup) lookup-option) (case key
((eq? key 'register-option) register-option) ((lookup) lookup-option)
((eq? key 'register-callback) register-callback) ((register-option) register-option)
((eq? key 'unregister-callback-id) unregister-callback-id) ((register-callback) register-callback)
((eq? key 'for-each) options-for-each) ((unregister-callback-id) unregister-callback-id)
((eq? key 'for-each-general) options-for-each-general) ((for-each) options-for-each)
((eq? key 'generate-restore-forms) generate-restore-forms) ((for-each-general) options-for-each-general)
((eq? key 'clear-changes) clear-changes) ((generate-restore-forms) generate-restore-forms)
((eq? key 'run-callbacks) run-callbacks) ((clear-changes) clear-changes)
(else (gnc:warn "options: bad key: " key "\n")))) ((run-callbacks) run-callbacks)
(else (gnc:warn "options: bad key: " key "\n"))))
dispatch) dispatch)
@ -394,9 +498,10 @@
(gnc:option-db-register-option db_handle option)) (gnc:option-db-register-option db_handle option))
options)) 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)) (let ((code (gnc:generate-restore-forms options options-string))
(port (open file (logior O_WRONLY O_CREAT O_TRUNC)))) (port (open file (logior O_WRONLY O_CREAT O_TRUNC))))
(if port (begin (if port (begin
(display header port)
(display code port) (display code port)
(close port))))) (close port)))))

View File

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

View File

@ -1,6 +1,5 @@
;;;; Preferences... ;;;; Preferences...
(use-modules (ice-9 slib))
(require 'sort) (require 'sort)
(require 'hash-table) (require 'hash-table)
@ -58,11 +57,18 @@
(gnc:make-home-dir) (gnc:make-home-dir)
(gnc:save-options gnc:*options-entries* (gnc:save-options gnc:*options-entries*
(symbol->string '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 ;;;;;; Create default options and config vars
;; Account Types options
(gnc:register-configuration-option (gnc:register-configuration-option
(gnc:make-simple-boolean-option (gnc:make-simple-boolean-option
"Account Types" "Show bank accounts" "Account Types" "Show bank accounts"
@ -119,6 +125,8 @@
"k" "Show equity accounts in the account tree." #t)) "k" "Show equity accounts in the account tree." #t))
;; Account Fields options
(gnc:register-configuration-option (gnc:register-configuration-option
(gnc:make-simple-boolean-option (gnc:make-simple-boolean-option
"Account Fields" "Show account name" "Account Fields" "Show account name"
@ -159,6 +167,9 @@
"Account Fields" "Show account balance" "Account Fields" "Show account balance"
"h" "Show the account balance column in the account tree." #t)) "h" "Show the account balance column in the account tree." #t))
;; International options
(gnc:register-configuration-option (gnc:register-configuration-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
"International" "Date Format" "International" "Date Format"
@ -166,8 +177,8 @@
(list #(us "US" "US-style: mm/dd/yyyy") (list #(us "US" "US-style: mm/dd/yyyy")
#(uk "UK" "UK-style dd/mm/yyyy") #(uk "UK" "UK-style dd/mm/yyyy")
#(ce "Europe" "Continental Europe: dd.mm.yyyy") #(ce "Europe" "Continental Europe: dd.mm.yyyy")
#(iso "ISO" "ISO Standard: yyyy-mm-dd") #(iso "ISO" "ISO Standard: yyyy-mm-dd"))))
#(locale "Locale" "Take from system locale")))) ; #(locale "Locale" "Take from system locale"))))
;; hack alert - we should probably get the default new account currency ;; hack alert - we should probably get the default new account currency
;; from the locale ;; from the locale
@ -182,6 +193,9 @@
"International" "Use 24-hour time format" "International" "Use 24-hour time format"
"c" "Use a 24 hour (instead of a 12 hour) time format." #f)) "c" "Use a 24 hour (instead of a 12 hour) time format." #f))
;; Register options
(gnc:register-configuration-option (gnc:register-configuration-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
"Register" "Default Register Mode" "Register" "Default Register Mode"
@ -200,15 +214,150 @@
"Register" "Auto-Raise Lists" "Register" "Auto-Raise Lists"
"b" "Automatically raise the list of accounts or actions during input." #t)) "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:register-configuration-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
"General" "Toolbar Buttons" "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 'icons_and_text
(list #(icons_and_text "Icons and Text" "Show both icons and text") (list #(icons_and_text "Icons and Text" "Show both icons and text")
#(icons_only "Icons only" "Show icons only") #(icons_only "Icons only" "Show icons only")
#(text_only "Text only" "Show text 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* (define gnc:*arg-show-version*
(gnc:make-config-var (gnc:make-config-var
"Show version." "Show version."
@ -286,3 +435,87 @@ the current value of the path."
#f))) #f)))
equal? equal?
'(default))) '(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) (require 'hash-table)
(gnc:support "report.scm") (gnc:support "report.scm")
@ -46,17 +45,25 @@
(call-report rendering-thunk options))))) (call-report rendering-thunk options)))))
(define (gnc:report-menu-setup win) (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 (hash-for-each
(lambda (name report) (lambda (name report)
(gnc:extensions-menu-add-item (define item
(string-append "Report: " name) (gnc:make-menu-item
(string-append "Display the " name " report.") ((menu-namer 'add-name) name)
(lambda () (string-append "Display the " name " report.")
(let ((options (false-if-exception (gnc:report-new-options report)))) (list "_Reports" "")
(gnc:report-window (string-append "Report: " name) (lambda ()
(lambda () (gnc:run-report name options)) (let ((options (false-if-exception (gnc:report-new-options report))))
options))))) (gnc:report-window (string-append "Report: " name)
(lambda () (gnc:run-report name options))
options)))))
(gnc:add-extension item))
*gnc:_report-info_*)) *gnc:_report-info_*))
(define (gnc:define-report version name option-generator rendering-thunk) (define (gnc:define-report version name option-generator rendering-thunk)

View File

@ -1,43 +1,56 @@
;; -*-scheme-*- ;; -*-scheme-*-
;; average-balance.scm ;; average-balance.scm
;; Report history of account balance and other info ;; Report history of account balance and other info
;; Also graphs the information with gnuplot ;; Plots the information with gnuplot
;; Matt Martin <mgmartin@abacusnet.net> ;;
;; 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 'hash-table)
(require 'printf)
;hack alert - is this line necessary? (gnc:depend "structure.scm")
(gnc:depend "text-export.scm")
(define datelist '()) ;; Modify a date
(define (moddate op adate delta)
;; Add delta to date, return result
(define (incdate adate delta)
(let ((newtm (localtime (car adate)))) (let ((newtm (localtime (car adate))))
(begin (begin
(set-tm:mday newtm (+ (tm:mday newtm) (tm:mday delta))) (set-tm:sec newtm (op (tm:sec newtm) (tm:sec delta)))
(set-tm:mon newtm (+ (tm:mon newtm) (tm:mon delta))) (set-tm:min newtm (op (tm:min newtm) (tm:min delta)))
(set-tm:year newtm (+ (tm:year newtm) (tm:year 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)))) (let ((time (car (mktime newtm))))
(cons time 0)) (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) (define (dateloop curd endd incr)
(cond ((gnc:timepair-later-date curd endd) (cond ((gnc:timepair-later curd endd)
(cons curd (dateloop (incdate curd incr) endd incr))) (let ((nextd (incdate curd incr)))
(else (list curd)) (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 (runavg-options-generator)
(define gnc:*runavg-track-options* (gnc:new-options)) (define gnc:*runavg-track-options* (gnc:new-options))
@ -78,12 +91,24 @@
"d" "Do transaction report on this account" "d" "Do transaction report on this account"
(lambda () (lambda ()
(let ((current-accounts (gnc:get-current-accounts)) (let ((current-accounts (gnc:get-current-accounts))
(num-accounts (gnc:group-get-num-accounts (gnc:get-current-group))) (num-accounts
(first-account (gnc:group-get-account (gnc:get-current-group) 0))) (gnc:group-get-num-accounts (gnc:get-current-group))))
(cond ((not (null? current-accounts)) (list (car current-accounts)))
((> num-accounts 0) (list first-account)) (cond ((not (null? current-accounts)) current-accounts)
(else ())))) (else
#f #f)) (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:register-runavg-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
@ -96,16 +121,21 @@
#(YearDelta "Year" "Year") #(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:register-runavg-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
"Report Options" "Plot Type" "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") (list #(NoPlot "Nothing" "Make No Plot")
#(AvgBalPlot "Average" "Average Balance") #(AvgBalPlot "Average" "Average Balance")
#(GainPlot "Net Gain" "Net Gain") #(GainPlot "Net Gain" "Net Gain")
#(GLPlot "Gain/Loss" "Gain And Loss") #(GLPlot "Gain/Loss" "Gain And Loss")
))) )))
gnc:*runavg-track-options*) gnc:*runavg-track-options*)
; A reference zero date ; A reference zero date
@ -121,6 +151,9 @@
zd zd
)) ))
(define SecDelta (let ((ddt (eval zdate)))
(set-tm:sec ddt 1)
ddt))
(define YearDelta (let ((ddt (eval zdate))) (define YearDelta (let ((ddt (eval zdate)))
(set-tm:year ddt 1) (set-tm:year ddt 1)
ddt)) ddt))
@ -139,12 +172,13 @@
(set-tm:mon ddt 1) (set-tm:mon ddt 1)
ddt)) ddt))
(define AvgBalPlot "using 1:2:3:4 t 'Average Balance' with errorbars") ;; Plot strings
(define GainPlot "using 1:5 t 'Net Gain' with linespoints") (define AvgBalPlot "using 2:3:4:5 t 'Average Balance' with errorbars, '' using 2:3 smooth sbezier t '' with lines")
(define GLPlot "using 1:7 t 'Losses' with lp, '' using 1:6 t 'Gains' with lp") (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 "") (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) (define (gnc:for-each-split-in-account account thunk)
(gnc:for-loop (lambda (x) (thunk (gnc:account-get-split account x))) (gnc:for-loop (lambda (x) (thunk (gnc:account-get-split account x)))
0 (gnc:account-get-split-count account) 1)) 0 (gnc:account-get-split-count account) 1))
@ -163,30 +197,14 @@
(define (gnc:split-get-account-name split) (define (gnc:split-get-account-name split)
(gnc:account-get-name (gnc:split-get-account split))) (gnc:account-get-name (gnc:split-get-account split)))
;; timepair manipulation functions (define (gnc:timepair-to-ldatestring tp)
;; hack alert - these should probably be put somewhere else
;; and be implemented PROPERLY rather than hackily
(define (gnc:timepair-to-datestring tp)
(let ((bdtime (localtime (car tp)))) (let ((bdtime (localtime (car tp))))
(strftime "%m/%d/%Y" bdtime))) (strftime "%m/%d/%Y" bdtime)))
;; Find difference in seconds (?) between time 1 and time2 ;; Find difference in seconds (?) between time 1 and time2
(define (gnc:timepair-delta t1 t2) (define (gnc:timepair-delta t1 t2)
(let ((time1 (car (gnc:timepair-canonical-day-time t1))) (- (car t2) (car 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)
; Convert to string ; Convert to string
(define (tostring val) (define (tostring val)
@ -205,11 +223,13 @@
; Create an html table row from a list of entries ; Create an html table row from a list of entries
(define (html-table-row lst) (define (html-table-row lst)
(string-append (cond ((string? lst) lst)
(sprintf #f "<TR>") (else
(apply string-append (map html-table-col lst)) (string-append
(sprintf #f "</TR>\n") (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 ; Create an html table from a list of rows, each containing
@ -227,7 +247,7 @@
) )
(define (html-table-header vec) (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) (define (html-table-footer)
@ -274,89 +294,199 @@
) )
) )
;; Reset accumulators between time intervals ;; Returns sum of all vector elements after the first
(define (resetvals bal curdate) (define (vector-sum v)
(set! tempmax bal) (let ((sum 0))
(set! tempmin bal) (gnc:for-loop (lambda(i) (set! sum (+ sum (car (vector-ref v i)))))
(set! prevdate curdate) 1 (vector-length v) 1)
(set! avgaccum 0) sum))
(set! lossaccum 0)
(set! gainaccum 0)
)
; ; Datelist entry operators
; Reduce a list of splits tl to a list of values at each date in datelist dl (define (dl:begin dl) (car dl))
; (define (dl:end dl) (car (cdr dl)))
(define (reduce-split-list dl tl pt)
(cond ((null? dl) '()) ;; End of recursion (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" (define (procvals)
(ct (car dl)) (let ((curbal (vector-sum (car (cdr (av 'x 0))))))
(val 0)) (set! balmin (min balmin curbal))
(set! balmax (max balmax curbal))))
(begin (define (accbal beg end)
(cond ( (not (null? tl)) (let ((curbal (vector-sum (car (cdr (av 'x 0))))))
;; Get latest split values if any remain (set! avgaccum (+ avgaccum
(set! bal (gnc:split-get-balance (car tl))) (* curbal
(set! val (gnc:split-get-value (car tl))) (gnc:timepair-delta beg end)))))
(set! ct (gnc:split-get-transaction-date (car tl))) )
))
(cond ; past time interval bound ?
((or(gnc:timepair-later-date (car dl) ct ) (null? tl))
(cond ; Is this the first interval ? (define (calc-in-interval d tl)
((= (car zdate) (car prevdate) ) (cond ((not (null? tl))
; Start first date interval
(begin (let* ((bd (dl:begin d)) ; begin date
(resetvals bal (car dl)) (ed (dl:end d)) ; end date
(reduce-split-list (cdr dl) tl (car dl)) (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" ((gnc:timepair-later cd ed) ;split is in the interval
(list (accbal prevdate cd)
(gnc:timepair-to-datestring (car dl)) (procvals)
(let ((dlta (gnc:timepair-delta prevdate (car dl)))) (bals 'put an (gnc:split-get-balance cs))
(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)
))
)
)))))
(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 acctcurrency "USD")
(define acctname "") (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 (gnc:define-report
;; version ;; version
1 1
@ -369,8 +499,10 @@
(let* ( (let* (
(begindate (gnc:option-value (begindate (gnc:option-value
(gnc:lookup-option options "Report Options" "From"))) (gnc:lookup-option options "Report Options" "From")))
(enddate (gnc:lookup-option options "Report Options" "To")) (enddate (gnc:option-value
(stepsize (gnc:lookup-option options "Report Options" "Step Size")) (gnc:lookup-option options "Report Options" "To")))
(stepsize (gnc:option-value
(gnc:lookup-option options "Report Options" "Step Size")))
(plotstr (gnc:option-value (plotstr (gnc:option-value
(gnc:lookup-option options "Report Options" "Plot Type"))) (gnc:lookup-option options "Report Options" "Plot Type")))
@ -378,45 +510,94 @@
(accounts (gnc:option-value (accounts (gnc:option-value
(gnc:lookup-option options (gnc:lookup-option options
"Report Options" "Account"))) "Report Options" "Account")))
(dosubs (gnc:option-value
(gnc:lookup-option options
"Report Options" "Sub-Accounts")))
(prefix (list "<HTML>" "<BODY>")) (prefix (list "<HTML>" "<BODY>"))
(suffix (list "</BODY>" "</HTML>")) (suffix (list "</BODY>" "</HTML>"))
(collist (collist
(list "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss")) (list "Beginning" "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss"))
(report-lines '()) (report-lines '())
(rept-data '()) (rept-data '())
(sum-data '())
(tempstruct '())
(rept-text "") (rept-text "")
(gncq (gnc:malloc-query))
(slist '())
) )
(gnc:init-query gncq)
(generate-datelist
begindate
(gnc:option-value enddate)
(gnc:option-value stepsize))
(if (null? accounts) (if (null? accounts)
(set! report-lines (set! report-lines
(list "<TR><TD>You have not selected an account.</TD></TR>")) (list "<TR><TD>You have not selected an account.</TD></TR>"))
(begin (begin
; Grab account names
(set! acctname (gnc:account-get-name (car accounts))) (set! acctname (gnc:account-get-name (car accounts)))
(set! acctcurrency (gnc:account-get-currency (car accounts))) (map (lambda(an)
(gnc:for-each-split-in-account (set! acctname
(car accounts) (string-append
(lambda (split) acctname
(set! report-lines " , "
(append! report-lines (list split))))))) (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 (length report-lines))
(display " Splits\n") (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 (set! rept-text
(html-table (html-table
collist 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))) (if (not (equal? NoPlot (eval plotstr)))
(let* ((fn "/tmp/gncplot.dat") (let* ((fn "/tmp/gncplot.dat")
(preplot (string-append (preplot (string-append
@ -435,6 +616,6 @@
(string-append "echo \"" preplot "plot '" fn "'" (eval plotstr) (string-append "echo \"" preplot "plot '" fn "'" (eval plotstr)
"\"|gnuplot -persist " ))) "\"|gnuplot -persist " )))
) )
(append prefix (list "Report for " acctname "<p>\n" )
(append prefix (list rept-text) suffix))) (list rept-text) suffix)))
) )

View File

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

View File

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

View File

@ -21,7 +21,7 @@
(define (gnc:register-dummy-option new-option) (define (gnc:register-dummy-option new-option)
(gnc:register-option gnc:*dummy-options* 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', ;; and is named 'Boolean Option'. Its sorting key is 'a',
;; thus it will come before options with sorting keys ;; thus it will come before options with sorting keys
;; 'b', 'c', etc. in the same section. The default value ;; 'b', 'c', etc. in the same section. The default value
@ -30,7 +30,7 @@
;; the mouse pointer over the option. ;; the mouse pointer over the option.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-simple-boolean-option (gnc:make-simple-boolean-option
"Page One" "Boolean Option" "Hello, World!" "Boolean Option"
"a" "This is a boolean option." #t)) "a" "This is a boolean option." #t))
;; This is a multichoice option. The user can choose between ;; This is a multichoice option. The user can choose between
@ -40,8 +40,8 @@
;; value is 'third. ;; value is 'third.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-multichoice-option (gnc:make-multichoice-option
"Page Two" "Multi Choice Option" "Hello, World!" "Multi Choice Option"
"a" "This is a multi choice option." 'third "b" "This is a multi choice option." 'third
(list #(first "First Option" "Help for first option.") (list #(first "First Option" "Help for first option.")
#(second "Second Option" "Help for second option.") #(second "Second Option" "Help for second option.")
#(third "Third Option" "Help for third option.") #(third "Third Option" "Help for third option.")
@ -54,8 +54,8 @@
;; other key is 'a'. ;; other key is 'a'.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-string-option (gnc:make-string-option
"Page Two" "String Option" "Hello, World!" "String Option"
"b" "This is a string option" "Hello, World")) "c" "This is a string option" "Hello, World"))
;; This is a date/time option. The user can pick a date and, ;; This is a date/time option. The user can pick a date and,
;; possibly, a time. Times are stored as a pair ;; possibly, a time. Times are stored as a pair
@ -65,8 +65,8 @@
;; time. ;; time.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-date-option (gnc:make-date-option
"Time and Date" "Just a Date Option" "Hello, World!" "Just a Date Option"
"a" "This is a date option" "d" "This is a date option"
(lambda () (cons (current-time) 0)) (lambda () (cons (current-time) 0))
#f)) #f))
@ -74,11 +74,26 @@
;; the time. ;; the time.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-date-option (gnc:make-date-option
"Time and Date" "Time and Date Option" "Hello, World!" "Time and Date Option"
"b" "This is a date option with time" "e" "This is a date option with time"
(lambda () (cons (current-time) 0)) (lambda () (cons (current-time) 0))
#t)) #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 ;; This is an account list option. The user can select one
;; or (possibly) more accounts from the list of accounts ;; or (possibly) more accounts from the list of accounts
;; in the current file. Values are scheme handles to actual ;; in the current file. Values are scheme handles to actual
@ -96,11 +111,20 @@
;; selected account in the main window, if any. ;; selected account in the main window, if any.
(gnc:register-dummy-option (gnc:register-dummy-option
(gnc:make-account-list-option (gnc:make-account-list-option
"Page One" "An account list option" "Hello, World!" "An account list option"
"b" "This is an account list option" "g" "This is an account list option"
(lambda () (gnc:get-current-accounts)) (lambda () (gnc:get-current-accounts))
#f #t)) #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*) gnc:*dummy-options*)
;; This is a helper function to generate an html list of account names ;; 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 ;; options in the set of options given to the function. This set will
;; be generated by the options generator above. ;; be generated by the options generator above.
;; Use (gnc:lookup-option options section name) to get the option. ;; 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 (multop (gnc:lookup-option options
"Page Two" "Multi Choice Option")) "Hello, World!" "Multi Choice Option"))
(strop (gnc:lookup-option options "Page Two" "String Option")) (strop (gnc:lookup-option options
"Hello, World!" "String Option"))
(dateop (gnc:lookup-option options (dateop (gnc:lookup-option options
"Time and Date" "Just a Date Option")) "Hello, World!" "Just a Date Option"))
(dateop2 (gnc:lookup-option options (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 (account-list-op (gnc:lookup-option options
"Page One" "Hello, World!"
"An account list option"))) "An account list option"))
(let ((time-string (strftime "%c" (localtime (current-time)))) (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 (date-string (strftime "%x" (localtime (car (gnc:option-value
dateop))))) dateop)))))
(date-string2 (strftime "%c" (date-string2 (strftime "%x %X"
(localtime (car (gnc:option-value (localtime (car (gnc:option-value
dateop2)))))) 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 ;; Here's where we generate the html. A real report would need
;; much more code and involve many more utility functions. See ;; much more code and involve many more utility functions. See
;; the other reports for details. Note that you can used nested ;; the other reports for details. Note that you can used nested
;; lists here, as well as arbitrary functions. ;; lists here, as well as arbitrary functions.
(list (list
"<html>" "<html>"
"<body>" "<body bgcolor=" (gnc:color-option->html colorop) ">"
"<h2>Hello, World Report</h2>" "<h2>Hello, World</h2>"
(list "<p>" (list "<p>"
"This is a sample GnuCash report. " "This is a sample GnuCash report. "

View File

@ -3,8 +3,6 @@
;; Report on all transactions in an account ;; Report on all transactions in an account
;; Robert Merkel (rgmerk@mira.net) ;; Robert Merkel (rgmerk@mira.net)
(use-modules (ice-9 slib))
(require 'printf)
(require 'sort) (require 'sort)
;hack alert - is this line necessary? ;hack alert - is this line necessary?
@ -215,7 +213,7 @@
(define (gnc:tr-report-get-first-acc-name split-scm) (define (gnc:tr-report-get-first-acc-name split-scm)
(let ((other-splits (gnc:tr-report-get-other-splits 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))))) (else (caar other-splits)))))
;;; something like ;;; 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 ;; None of these loads will be affected by any command line arguments
;; since arguments aren't parsed until gnc:main is executed. ;; 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 "macros.scm")
(gnc:load "config-var.scm") (gnc:load "config-var.scm")
(gnc:load "utilities.scm") (gnc:load "utilities.scm")

View File

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