mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Last bigpatch.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2024 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
bd1d5e2c62
commit
11529e91c1
@ -33,6 +33,7 @@
|
||||
#include "Transaction.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/** GLOBALS *********************************************************/
|
||||
/* These are globals because they describe the state of the entire session.
|
||||
* The is, there must be only one instance of these per GUI session.
|
||||
@ -209,7 +210,7 @@ xaccLedgerDisplaySimple (Account *acc)
|
||||
|
||||
xaccLedgerDisplay *
|
||||
xaccLedgerDisplayAccGroup (Account *acc)
|
||||
{
|
||||
{
|
||||
xaccLedgerDisplay *retval;
|
||||
Account **list;
|
||||
int ledger_type;
|
||||
@ -271,7 +272,7 @@ xaccLedgerDisplayAccGroup (Account *acc)
|
||||
|
||||
if (list) _free (list);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
static gncUIWidget
|
||||
xaccLedgerDisplayParent(void *user_data)
|
||||
@ -287,6 +288,20 @@ xaccLedgerDisplayParent(void *user_data)
|
||||
return (regData->get_parent)(regData);
|
||||
}
|
||||
|
||||
static void
|
||||
xaccLedgerDisplaySetHelp(void *user_data, const char *help_str)
|
||||
{
|
||||
xaccLedgerDisplay *regData = user_data;
|
||||
|
||||
if (regData == NULL)
|
||||
return;
|
||||
|
||||
if (regData->set_help == NULL)
|
||||
return;
|
||||
|
||||
(regData->set_help)(regData, help_str);
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* xaccLedgerDisplayLedger *
|
||||
* opens up a ledger window for a list of accounts *
|
||||
@ -300,7 +315,7 @@ xaccLedgerDisplayParent(void *user_data)
|
||||
|
||||
xaccLedgerDisplay *
|
||||
xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
|
||||
{
|
||||
{
|
||||
xaccLedgerDisplay *regData = NULL;
|
||||
|
||||
/******************************************************************\
|
||||
@ -340,6 +355,7 @@ xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
|
||||
regData->redraw = NULL;
|
||||
regData->destroy = NULL;
|
||||
regData->get_parent = NULL;
|
||||
regData->set_help = NULL;
|
||||
regData->gui_hook = NULL;
|
||||
regData->dirty = 0;
|
||||
regData->balance = 0.0;
|
||||
@ -373,7 +389,9 @@ xaccLedgerDisplayGeneral (Account *lead_acc, Account **acclist, int ledger_type)
|
||||
* but will not do the gui init */
|
||||
regData->ledger = xaccMallocSplitRegister (ledger_type);
|
||||
|
||||
xaccSRSetData(regData->ledger, regData, xaccLedgerDisplayParent);
|
||||
xaccSRSetData(regData->ledger, regData,
|
||||
xaccLedgerDisplayParent,
|
||||
xaccLedgerDisplaySetHelp);
|
||||
|
||||
regData->dirty = 1;
|
||||
xaccLedgerDisplayRefresh (regData);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "SplitLedger.h"
|
||||
#include "Transaction.h"
|
||||
|
||||
|
||||
/* the MAX_QUERY_SPLITS define determines how many transactions should be shown
|
||||
* in the register. Its set to a default of 30. But this should be converted
|
||||
* into a user-configurable value. So hack-alert on the configuration aspect.
|
||||
@ -72,6 +73,7 @@ struct _xaccLedgerDisplay {
|
||||
void (*redraw) (xaccLedgerDisplay *); /* redraw callback */
|
||||
void (*destroy) (xaccLedgerDisplay *); /* destroy callback */
|
||||
gncUIWidget (*get_parent) (xaccLedgerDisplay *); /* get parent widget */
|
||||
void (*set_help) (xaccLedgerDisplay *, const char *); /* help string */
|
||||
};
|
||||
|
||||
|
||||
|
@ -126,6 +126,9 @@ gnc_transaction_ui_refresh(Transaction *trans)
|
||||
Split *split;
|
||||
int i, num_splits;
|
||||
|
||||
if (trans == NULL)
|
||||
return;
|
||||
|
||||
xaccTransDisplayRefresh(trans);
|
||||
|
||||
num_splits = xaccTransCountSplits(trans);
|
||||
|
@ -127,7 +127,10 @@ struct _SRInfo
|
||||
void *user_data;
|
||||
|
||||
/* hook to get parent widget */
|
||||
gncUIWidget (*get_parent) (void * user_data);
|
||||
SRGetParentCallback get_parent;
|
||||
|
||||
/* hook to set help string */
|
||||
SRSetHelpCallback set_help;
|
||||
};
|
||||
|
||||
|
||||
@ -156,6 +159,8 @@ static int force_double_entry_awareness = 0;
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static short module = MOD_LEDGER;
|
||||
|
||||
/* The character used to separate accounts. */
|
||||
static char account_separator = ':';
|
||||
|
||||
/* static prototypes */
|
||||
static Transaction * xaccSRGetTrans (SplitRegister *reg,
|
||||
@ -220,7 +225,8 @@ xaccSRGetParent(SplitRegister *reg)
|
||||
|
||||
void
|
||||
xaccSRSetData(SplitRegister *reg, void *user_data,
|
||||
SRGetParentCallback get_parent)
|
||||
SRGetParentCallback get_parent,
|
||||
SRSetHelpCallback set_help)
|
||||
{
|
||||
SRInfo *info = xaccSRGetInfo(reg);
|
||||
|
||||
@ -228,6 +234,13 @@ xaccSRSetData(SplitRegister *reg, void *user_data,
|
||||
|
||||
info->user_data = user_data;
|
||||
info->get_parent = get_parent;
|
||||
info->set_help = set_help;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSRSetAccountSeparator(char separator)
|
||||
{
|
||||
account_separator = separator;
|
||||
}
|
||||
|
||||
/* ======================================================== */
|
||||
@ -387,6 +400,20 @@ LedgerTraverse (Table *table,
|
||||
|
||||
/* ======================================================== */
|
||||
|
||||
static void
|
||||
LedgerSetHelp (Table *table, const char *help_str, void *client_data)
|
||||
{
|
||||
SplitRegister *reg = client_data;
|
||||
SRInfo *info = xaccSRGetInfo(reg);
|
||||
|
||||
if (info->set_help == NULL)
|
||||
return;
|
||||
|
||||
info->set_help(info->user_data, help_str);
|
||||
}
|
||||
|
||||
/* ======================================================== */
|
||||
|
||||
static void
|
||||
LedgerDestroy (SplitRegister *reg)
|
||||
{
|
||||
@ -484,10 +511,8 @@ xaccSRGetCurrentTrans (SplitRegister *reg)
|
||||
}
|
||||
|
||||
split = (Split *) reg->table->user_data[vr][vc];
|
||||
if (split == NULL) {
|
||||
PERR ("Internal Error: xaccSRGetCurrentTrans(): no parent \n");
|
||||
if (split == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return xaccSplitGetParent(split);
|
||||
}
|
||||
@ -961,8 +986,8 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
}
|
||||
|
||||
if (MOD_MEMO & changed) {
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_MEMO: %s\n", reg->memoCell->value);
|
||||
xaccSplitSetMemo (split, reg->memoCell->value);
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_MEMO: %s\n", reg->memoCell->cell.value);
|
||||
xaccSplitSetMemo (split, reg->memoCell->cell.value);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
@ -980,13 +1005,18 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
/* do some reparenting. Insertion into new account will automatically
|
||||
* delete this split from the old account */
|
||||
old_acc = xaccSplitGetAccount (split);
|
||||
new_acc = xaccGetAccountByName (trans, reg->xfrmCell->cell.value);
|
||||
new_acc = xaccGetAccountByFullName (trans, reg->xfrmCell->cell.value,
|
||||
account_separator);
|
||||
|
||||
if (old_acc != new_acc)
|
||||
{
|
||||
xaccAccountInsertSplit (new_acc, split);
|
||||
|
||||
/* make sure any open windows of the old account get redrawn */
|
||||
gnc_account_ui_refresh(old_acc);
|
||||
gnc_refresh_main_window();
|
||||
}
|
||||
}
|
||||
|
||||
if (MOD_MXFRM & changed) {
|
||||
Split *other_split = NULL;
|
||||
@ -1023,7 +1053,11 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
/* do some reparenting. Insertion into new account will automatically
|
||||
* delete from the old account */
|
||||
old_acc = xaccSplitGetAccount (other_split);
|
||||
new_acc = xaccGetAccountByName (trans, reg->mxfrmCell->cell.value);
|
||||
new_acc = xaccGetAccountByFullName (trans, reg->mxfrmCell->cell.value,
|
||||
account_separator);
|
||||
|
||||
if (old_acc != new_acc)
|
||||
{
|
||||
xaccAccountInsertSplit (new_acc, other_split);
|
||||
|
||||
/* make sure any open windows of the old account get redrawn */
|
||||
@ -1031,6 +1065,7 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
gnc_refresh_main_window();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MOD_XTO & changed) {
|
||||
/* hack alert -- implement this */
|
||||
@ -1043,10 +1078,17 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
*/
|
||||
if ((MOD_AMNT | MOD_NAMNT) & changed) {
|
||||
double new_amount;
|
||||
double credit;
|
||||
double debit;
|
||||
|
||||
if (MOD_AMNT & changed) {
|
||||
new_amount = (reg->creditCell->amount) - (reg->debitCell->amount);
|
||||
credit = xaccGetPriceCellValue(reg->creditCell);
|
||||
debit = xaccGetPriceCellValue(reg->debitCell);
|
||||
new_amount = credit - debit;
|
||||
} else {
|
||||
new_amount = (reg->ndebitCell->amount) - (reg->ncreditCell->amount);
|
||||
credit = xaccGetPriceCellValue(reg->ncreditCell);
|
||||
debit = xaccGetPriceCellValue(reg->ndebitCell);
|
||||
new_amount = debit - credit;
|
||||
}
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_AMNT: %f\n", new_amount);
|
||||
if ((EQUITY_REGISTER == (reg->type & REG_TYPE_MASK)) ||
|
||||
@ -1062,9 +1104,13 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
|
||||
if (MOD_PRIC & changed) {
|
||||
Account *acc;
|
||||
double price;
|
||||
int n;
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_PRIC: %f\n", reg->priceCell->amount);
|
||||
xaccSplitSetSharePrice (split, reg->priceCell->amount);
|
||||
|
||||
price = xaccGetPriceCellValue(reg->priceCell);
|
||||
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_PRIC: %f\n", price);
|
||||
xaccSplitSetSharePrice (split, price);
|
||||
|
||||
/* Here we handle a very special case: the user just created
|
||||
* an account, which now has two splits in it, and the user
|
||||
@ -1089,7 +1135,7 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
if (DEQ (currprice, 1.0)) {
|
||||
t = xaccSplitGetParent (s);
|
||||
xaccTransBeginEdit (t, 0);
|
||||
xaccSplitSetSharePrice (s, reg->priceCell->amount);
|
||||
xaccSplitSetSharePrice (s, price);
|
||||
xaccTransCommitEdit (t);
|
||||
}
|
||||
}
|
||||
@ -1097,8 +1143,10 @@ xaccSRSaveRegEntry (SplitRegister *reg, Transaction *newtrans)
|
||||
}
|
||||
|
||||
if (MOD_VALU & changed) {
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_VALU: %f\n", reg->valueCell->amount);
|
||||
xaccSplitSetValue (split, (reg->valueCell->amount));
|
||||
double value = xaccGetPriceCellValue(reg->valueCell);
|
||||
|
||||
DEBUG ("xaccSRSaveRegEntry(): MOD_VALU: %f\n", value);
|
||||
xaccSplitSetValue (split, value);
|
||||
}
|
||||
|
||||
PINFO ("xaccSRSaveRegEntry(): finished saving split %s of trans %s \n",
|
||||
@ -1133,12 +1181,12 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
|
||||
char buff[2];
|
||||
double baln;
|
||||
int typo = reg->type & REG_TYPE_MASK;
|
||||
/* int style = reg->type & REG_STYLE_MASK; */
|
||||
|
||||
/* don't even bother doing a load if there is no current cursor */
|
||||
if (!(reg->table->current_cursor)) return;
|
||||
|
||||
ENTER ("SRLoadTransEntry(): s=%p commit=%d\n", split, do_commit);
|
||||
|
||||
if (!split) {
|
||||
/* we interpret a NULL split as a blank split */
|
||||
xaccSetDateCellValueSecs (reg->dateCell, 0);
|
||||
@ -1149,7 +1197,7 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
|
||||
xaccSetPriceCellValue (reg->balanceCell, 0.0);
|
||||
|
||||
xaccSetComboCellValue (reg->actionCell, "");
|
||||
xaccSetBasicCellValue (reg->memoCell, "");
|
||||
xaccSetQuickFillCellValue (reg->memoCell, "");
|
||||
xaccSetComboCellValue (reg->xfrmCell, "");
|
||||
xaccSetComboCellValue (reg->mxfrmCell, "");
|
||||
xaccSetDebCredCellValue (reg->debitCell,
|
||||
@ -1198,12 +1246,19 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
|
||||
* if there are exactly two splits.
|
||||
* xfrm is the "straight" display, "mxfrm" is the "mirrored" display.
|
||||
*/
|
||||
accname = xaccAccountGetName (xaccSplitGetAccount (split));
|
||||
accname = xaccAccountGetFullName (xaccSplitGetAccount (split),
|
||||
account_separator);
|
||||
xaccSetComboCellValue (reg->xfrmCell, accname);
|
||||
free(accname);
|
||||
|
||||
{
|
||||
Split *s = xaccGetOtherSplit (split);
|
||||
gncBoolean need_to_free = GNC_F;
|
||||
|
||||
if (s) {
|
||||
accname = xaccAccountGetName (xaccSplitGetAccount (s));
|
||||
accname = xaccAccountGetFullName (xaccSplitGetAccount (s),
|
||||
account_separator);
|
||||
need_to_free = GNC_T;
|
||||
} else {
|
||||
/* determine whether s is null because threre are three
|
||||
* or more splits, or whether there is only one ... */
|
||||
@ -1215,9 +1270,11 @@ xaccSRLoadTransEntry (SplitRegister *reg, Split *split, int do_commit)
|
||||
}
|
||||
}
|
||||
xaccSetComboCellValue (reg->mxfrmCell, accname);
|
||||
if (need_to_free)
|
||||
free(accname);
|
||||
}
|
||||
|
||||
xaccSetBasicCellValue (reg->memoCell, xaccSplitGetMemo (split));
|
||||
xaccSetQuickFillCellValue (reg->memoCell, xaccSplitGetMemo (split));
|
||||
|
||||
buff[0] = xaccSplitGetReconcile (split);
|
||||
buff[1] = 0x0;
|
||||
@ -1459,6 +1516,8 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
|
||||
CellBlock *lead_cursor;
|
||||
gncBoolean found_pending = GNC_F;
|
||||
|
||||
xaccSplitRegisterConfigColors (reg);
|
||||
|
||||
info->default_source_account = default_source_acc;
|
||||
|
||||
table = reg->table;
|
||||
@ -1546,8 +1605,9 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
|
||||
vrow ++;
|
||||
phys_row += reg->trans_cursor->numRows;
|
||||
|
||||
/* loop over all of the splits in the transaction */
|
||||
/* the do..while will automaticaly put a blank (null) split at the end */
|
||||
/* loop over all of the splits in the transaction. The
|
||||
* do..while will automaticaly put a blank (null) split
|
||||
* at the end. */
|
||||
trans = xaccSplitGetParent (split);
|
||||
j = 0;
|
||||
do {
|
||||
@ -1662,9 +1722,14 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
|
||||
|
||||
xaccRefreshTableGUI (table);
|
||||
|
||||
/* set the completion character for the xfer cells */
|
||||
xaccComboCellSetCompleteChar (reg->mxfrmCell, account_separator);
|
||||
xaccComboCellSetCompleteChar (reg->xfrmCell, account_separator);
|
||||
|
||||
/* enable callback for cursor user-driven moves */
|
||||
table->move_cursor = LedgerMoveCursor;
|
||||
table->traverse = LedgerTraverse;
|
||||
table->set_help = LedgerSetHelp;
|
||||
table->client_data = (void *) reg;
|
||||
}
|
||||
|
||||
@ -1677,6 +1742,7 @@ LoadXferCell (ComboCell *cell,
|
||||
char *base_currency, char *base_security)
|
||||
{
|
||||
Account * acc;
|
||||
char *name;
|
||||
int n;
|
||||
|
||||
ENTER ("LoadXferCell(): curr=%s secu=%s\n", base_currency, base_security);
|
||||
@ -1699,18 +1765,25 @@ LoadXferCell (ComboCell *cell,
|
||||
|
||||
DEBUG ("LoadXferCell(): curr=%s secu=%s acct=%s\n",
|
||||
curr, secu, xaccAccountGetName (acc));
|
||||
|
||||
if ( (!safe_strcmp(curr,base_currency)) ||
|
||||
(!safe_strcmp(curr,base_security)) ||
|
||||
(secu && (!safe_strcmp(secu,base_currency))) ||
|
||||
(secu && (!safe_strcmp(secu,base_security))) )
|
||||
{
|
||||
xaccAddComboCellMenuItem (cell, xaccAccountGetName (acc));
|
||||
name = xaccAccountGetFullName (acc, account_separator);
|
||||
if (name != NULL)
|
||||
{
|
||||
xaccAddComboCellMenuItem (cell, name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
LoadXferCell (cell, xaccAccountGetChildren (acc),
|
||||
base_currency, base_security);
|
||||
n++;
|
||||
acc = xaccGroupGetAccount (grp, n);
|
||||
}
|
||||
|
||||
LEAVE ("LoadXferCell()\n");
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ COMMON_SRCS := basiccell.c cellblock.c \
|
||||
datecell.c pricecell.c QuickFill.c quickfillcell.c \
|
||||
recncell.c splitreg.c \
|
||||
table-allgui.c table-html.c textcell.c
|
||||
MOTIF_SRCS := table-motif.c combocell-motif.c
|
||||
MOTIF_SRCS := table-motif.c combocell-motif.c quickfillcell-motif.c
|
||||
GNOME_SRCS := table-gnome.c
|
||||
QT_SRCS := table-qt.cpp combocell-qt.cpp
|
||||
CLEAN_SUBDIRS := gnome
|
||||
|
@ -110,23 +110,72 @@ xaccGetQuickFill( QuickFill *qf, char c )
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
QuickFill *
|
||||
xaccGetQuickFillStr( QuickFill *qf, const char *str )
|
||||
xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len )
|
||||
{
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
while (*str != '\0')
|
||||
while ((*str != '\0') && (len > 0))
|
||||
{
|
||||
if (qf == NULL)
|
||||
return NULL;
|
||||
|
||||
qf = qf->qf[CHAR_TO_INDEX(*str)];
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return qf;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
QuickFill *
|
||||
xaccGetQuickFillStr( QuickFill *qf, const char *str )
|
||||
{
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
return xaccGetQuickFillStrLen(qf, str, strlen(str));
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
QuickFill *
|
||||
xaccGetQuickFillUniqueLen( QuickFill *qf, int * length )
|
||||
{
|
||||
int last = 0;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
*length = 0;
|
||||
|
||||
if (qf == NULL)
|
||||
return NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
count = 0;
|
||||
for( i=0; i<QFNUM; i++ )
|
||||
{
|
||||
if (qf->qf[i] != NULL)
|
||||
{
|
||||
count++;
|
||||
if (count > 1)
|
||||
return qf;
|
||||
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return qf;
|
||||
|
||||
qf = qf->qf[last];
|
||||
(*length)++;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
void
|
||||
|
@ -66,6 +66,8 @@ QuickFill *xaccMallocQuickFill( void );
|
||||
void xaccFreeQuickFill( QuickFill *qf );
|
||||
QuickFill *xaccGetQuickFill( QuickFill *qf, char c );
|
||||
QuickFill *xaccGetQuickFillStr( QuickFill *qf, const char *str );
|
||||
QuickFill *xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len );
|
||||
QuickFill *xaccGetQuickFillUniqueLen( QuickFill *qf, int *len );
|
||||
void xaccQFInsertText( QuickFill *qf, const char *text, QuickFillSort );
|
||||
|
||||
/** GLOBALS *********************************************************/
|
||||
|
@ -43,6 +43,20 @@ BasicCell * xaccMallocBasicCell (void)
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
static char *
|
||||
BasicCellHelpValue(BasicCell *cell)
|
||||
{
|
||||
if ((cell->value != NULL) && (cell->value[0] != 0))
|
||||
return strdup(cell->value);
|
||||
|
||||
if (cell->blank_help != NULL)
|
||||
return strdup(cell->blank_help);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
void xaccInitBasicCell (BasicCell *cell)
|
||||
{
|
||||
cell->input_output = XACC_CELL_ALLOW_ALL;
|
||||
@ -50,15 +64,18 @@ void xaccInitBasicCell (BasicCell *cell)
|
||||
cell->fg_color = 0x0; /* black */
|
||||
cell->use_bg_color = 0; /* ignore the color */
|
||||
cell->use_fg_color = 0; /* ignore the color */
|
||||
cell->value = 0x0;
|
||||
cell->value = NULL;
|
||||
cell->blank_help = NULL;
|
||||
cell->changed = 0;
|
||||
cell->set_value = NULL;
|
||||
cell->enter_cell = NULL;
|
||||
cell->modify_verify = NULL;
|
||||
cell->direct_update = NULL;
|
||||
cell->leave_cell = NULL;
|
||||
cell->realize = NULL;
|
||||
cell->move = NULL;
|
||||
cell->destroy = NULL;
|
||||
cell->get_help_value = BasicCellHelpValue;
|
||||
cell->gui_private = NULL;
|
||||
}
|
||||
|
||||
@ -76,6 +93,10 @@ void xaccDestroyBasicCell (BasicCell *cell)
|
||||
free (cell->value);
|
||||
}
|
||||
|
||||
if (cell->blank_help) {
|
||||
free (cell->blank_help);
|
||||
}
|
||||
|
||||
/* help prevent access to freed memory */
|
||||
xaccInitBasicCell (cell);
|
||||
|
||||
@ -106,4 +127,35 @@ void xaccSetBasicCellValue (BasicCell *cell, const char *val)
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
void
|
||||
xaccSetBasicCellBlankHelp (BasicCell *cell, const char *blank_help)
|
||||
{
|
||||
if (cell == NULL)
|
||||
return;
|
||||
|
||||
if (cell->blank_help != NULL)
|
||||
free(cell->blank_help);
|
||||
|
||||
if (blank_help == NULL)
|
||||
cell->blank_help = NULL;
|
||||
else
|
||||
cell->blank_help = strdup(blank_help);
|
||||
}
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
char *
|
||||
xaccBasicCellGetHelp (BasicCell *cell)
|
||||
{
|
||||
if (cell == NULL)
|
||||
return NULL;
|
||||
|
||||
if (cell->get_help_value == NULL)
|
||||
return NULL;
|
||||
|
||||
return cell->get_help_value(cell);
|
||||
}
|
||||
|
||||
/* ================== end of file ====================== */
|
||||
|
@ -114,6 +114,14 @@
|
||||
* It must return a string, or void if it rejects the change.
|
||||
* The returned string will be used to update the cell value.
|
||||
*
|
||||
* The direct_update() callback is called to pass raw gui data
|
||||
* to the cell. The exact format of the data is determined
|
||||
* by the gui. The callback should return TRUE if the event
|
||||
* was handled, i.e., there is no need to call the modify
|
||||
* update. If the value needs to be changed, the newval_ptr
|
||||
* should be set to a malloc'd new value. The other arguments
|
||||
* work as above.
|
||||
*
|
||||
* Some memory management rules:
|
||||
* (1) the callback must not modify the values of old, change, new
|
||||
* (2) if the callback likes the new string, it may return the
|
||||
@ -177,6 +185,8 @@
|
||||
#ifndef __XACC_BASIC_CELL_H__
|
||||
#define __XACC_BASIC_CELL_H__
|
||||
|
||||
#include "gnc-common.h"
|
||||
|
||||
/* define a bitmask */
|
||||
#define XACC_CELL_ALLOW_NONE 0x0
|
||||
#define XACC_CELL_ALLOW_SHADOW 0x1
|
||||
@ -185,7 +195,6 @@
|
||||
#define XACC_CELL_ALLOW_EXACT_ONLY 0x4
|
||||
|
||||
typedef struct _BasicCell BasicCell;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
struct _BasicCell {
|
||||
|
||||
@ -200,6 +209,7 @@ struct _BasicCell {
|
||||
|
||||
/* ==================================================== */
|
||||
char * value; /* current value */
|
||||
char *blank_help; /* help when value is blank */
|
||||
unsigned int changed; /* 2^32-1 if value modified */
|
||||
|
||||
char input_output; /* zero if output-only */
|
||||
@ -221,6 +231,13 @@ struct _BasicCell {
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection);
|
||||
gncBoolean (*direct_update) (BasicCell *,
|
||||
const char *oldval,
|
||||
char **newval_ptr,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection,
|
||||
void *gui_data);
|
||||
const char * (*leave_cell) (BasicCell *,
|
||||
const char * current);
|
||||
|
||||
@ -232,6 +249,8 @@ struct _BasicCell {
|
||||
int phys_row, int phys_col);
|
||||
void (* destroy) (BasicCell *);
|
||||
|
||||
char * (*get_help_value) (BasicCell *);
|
||||
|
||||
/* general hook for gui-private data */
|
||||
void * gui_private;
|
||||
};
|
||||
@ -242,6 +261,8 @@ void xaccInitBasicCell (BasicCell *);
|
||||
void xaccDestroyBasicCell (BasicCell *);
|
||||
|
||||
void xaccSetBasicCellValue (BasicCell *, const char *);
|
||||
void xaccSetBasicCellBlankHelp (BasicCell *, const char *);
|
||||
char * xaccBasicCellGetHelp (BasicCell *);
|
||||
|
||||
#endif /* __XACC_BASIC_CELL_H__ */
|
||||
/* ------------------ end of file ---------------------- */
|
||||
|
@ -41,6 +41,7 @@ CellBlock * xaccMallocCellBlock (int numrows, int numcols)
|
||||
|
||||
arr->active_bg_color = 0xffffff; /* white */
|
||||
arr->passive_bg_color = 0xffffff; /* white */
|
||||
arr->passive_bg_color2 = 0xffffff; /* white */
|
||||
|
||||
arr->user_data = NULL;
|
||||
arr->cells = NULL;
|
||||
|
@ -88,10 +88,14 @@ struct _CellBlock {
|
||||
* the currently active cursor).
|
||||
*
|
||||
* The passive_bg_color is the default color for the cell background
|
||||
* (in argb format) when the cell block is not highlighted.
|
||||
* (in argb format) of the first row when the cell block is not highlighted.
|
||||
*
|
||||
* The passive_bg_color2 is the default color for cell backgrounds
|
||||
* in other rows of the cellblock when it is not highlighted.
|
||||
*/
|
||||
uint32 active_bg_color;
|
||||
uint32 passive_bg_color;
|
||||
uint32 passive_bg_color2;
|
||||
|
||||
/* other attributes */
|
||||
short *widths; /* column widths */
|
||||
|
@ -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 =================== */
|
||||
|
@ -61,6 +61,21 @@ void xaccAddComboCellMenuItem (ComboCell *, char * menustr);
|
||||
* to strict, i.e., only menu items are accepted. */
|
||||
void xaccComboCellSetStrict (ComboCell *, gncBoolean);
|
||||
|
||||
/* Only functional in Gnome, right now. Sets a character used
|
||||
* for special completion processing. */
|
||||
void xaccComboCellSetCompleteChar (ComboCell *, char);
|
||||
|
||||
/* Only functional in Gnome, right now. Sets a string which,
|
||||
* if the cell has that value, will be returned on an enter,
|
||||
* thus preventing the cell from being edited. This is used
|
||||
* for transactions with multiple splits. */
|
||||
void xaccComboCellSetIgnoreString (ComboCell *, const char *);
|
||||
|
||||
/* Only functional in Gnome, right now. Sets a string which,
|
||||
* if the cell has the ignore value, will be returned as the
|
||||
* help string. */
|
||||
void xaccComboCellSetIgnoreHelp (ComboCell *, const char *);
|
||||
|
||||
#endif /* __XACC_COMBO_CELL_H__ */
|
||||
|
||||
/* --------------- end of file ---------------------- */
|
||||
|
@ -54,8 +54,8 @@ static short module = MOD_REGISTER;
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
static
|
||||
void xaccParseDate (struct tm *parsed, const char * datestr)
|
||||
static void
|
||||
xaccParseDate (struct tm *parsed, const char * datestr)
|
||||
{
|
||||
int iday, imonth, iyear;
|
||||
if (!parsed) return;
|
||||
@ -121,6 +121,43 @@ xaccValidateDate (struct tm *date, int recur)
|
||||
}
|
||||
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
static char *
|
||||
DateCellHelpValue(BasicCell *bcell)
|
||||
{
|
||||
DateCell *cell = (DateCell *) bcell;
|
||||
|
||||
if ((bcell->value != NULL) && (bcell->value[0] != 0))
|
||||
{
|
||||
char string[1024];
|
||||
struct tm time;
|
||||
|
||||
memset(&time, 0, sizeof(time));
|
||||
|
||||
if (bcell->value != NULL)
|
||||
xaccParseDate (&time, bcell->value);
|
||||
else
|
||||
{
|
||||
time.tm_mday = cell->date.tm_mday;
|
||||
time.tm_mon = cell->date.tm_mon;
|
||||
time.tm_year = cell->date.tm_year;
|
||||
}
|
||||
|
||||
xaccValidateDate(&time, GNC_F);
|
||||
mktime(&time);
|
||||
|
||||
strftime(string, sizeof(string), "%A %d %B %Y", &time);
|
||||
|
||||
return strdup(string);
|
||||
}
|
||||
|
||||
if (bcell->blank_help != NULL)
|
||||
return strdup(bcell->blank_help);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
static const char *
|
||||
@ -150,32 +187,56 @@ DateMV (BasicCell *_cell,
|
||||
int *end_selection)
|
||||
{
|
||||
DateCell *cell = (DateCell *) _cell;
|
||||
gncBoolean accept = GNC_F;
|
||||
gncBoolean accel = GNC_F;
|
||||
struct tm *date;
|
||||
char buff[30];
|
||||
char *datestr;
|
||||
int accel=0;
|
||||
short accept=0;
|
||||
|
||||
/* if user hit backspace, accept the change */
|
||||
if (!change) accept=1;
|
||||
else if (0x0 == change[0]) accept=1;
|
||||
if (change == NULL) accept = GNC_T;
|
||||
else if (0x0 == change[0]) accept = GNC_T;
|
||||
else
|
||||
{
|
||||
int i, count = 0;
|
||||
char separator = dateSeparator();
|
||||
gncBoolean ok = GNC_T;
|
||||
|
||||
/* accept any numeric input */
|
||||
else if (isdigit (change[0])) accept=1;
|
||||
for (i=0; 0 != change[i]; i++)
|
||||
{
|
||||
/* accept only numbers or a date separator. Note that the
|
||||
* separator of '-' (for DATE_FORMAT_ISO) takes precedence
|
||||
* over the accelerator below! */
|
||||
if (!isdigit(change[i]) && (separator != change[i]))
|
||||
ok = GNC_F;
|
||||
|
||||
/* accept the separator character */
|
||||
/* Note that the separator of '-' (for DATE_FORMAT_ISO) takes precedence
|
||||
over the accelerator below! */
|
||||
else if (dateSeparator() == change[0]) accept=1;
|
||||
if (separator == change[i])
|
||||
count++;
|
||||
}
|
||||
|
||||
for (i=0; 0 != oldval[i]; i++)
|
||||
if (separator == oldval[i])
|
||||
count++;
|
||||
|
||||
if (2 < count)
|
||||
ok = GNC_F;
|
||||
|
||||
if (ok)
|
||||
accept = GNC_T;
|
||||
}
|
||||
|
||||
/* keep a copy of the new value */
|
||||
if (accept) {
|
||||
if (cell->cell.value) free (cell->cell.value);
|
||||
cell->cell.value = strdup (newval);
|
||||
xaccParseDate (&(cell->date), newval);
|
||||
return newval;
|
||||
}
|
||||
|
||||
/* otherwise, maybe its an accelerator key. */
|
||||
if (strlen(change) != 1)
|
||||
return NULL;
|
||||
|
||||
date = &(cell->date);
|
||||
|
||||
/* handle accelerator keys */
|
||||
@ -184,28 +245,28 @@ DateMV (BasicCell *_cell,
|
||||
case '=':
|
||||
/* increment day */
|
||||
date->tm_mday ++;
|
||||
accel = 1;
|
||||
accel = GNC_T;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
case '-':
|
||||
/* decrement day */
|
||||
date->tm_mday --;
|
||||
accel = 1;
|
||||
accel = GNC_T;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
case ']':
|
||||
/* increment month */
|
||||
date->tm_mon ++;
|
||||
accel = 1;
|
||||
accel = GNC_T;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
case '[':
|
||||
/* decrment month */
|
||||
date->tm_mon --;
|
||||
accel = 1;
|
||||
accel = GNC_T;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
@ -346,6 +407,7 @@ xaccInitDateCell (DateCell *cell)
|
||||
cell->cell.modify_verify = DateMV;
|
||||
cell->cell.leave_cell = DateLeave;
|
||||
cell->cell.set_value = setDateCellValue;
|
||||
cell->cell.get_help_value = DateCellHelpValue;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
@ -42,7 +42,7 @@ LIBS = -L$(prefix)/lib @LIBS@ \
|
||||
# See Makefile.common for information about these variables.
|
||||
GNOME_SRCS := gnucash-sheet.c gnucash-grid.c gnucash-color.c gnucash-cursor.c \
|
||||
gnucash-item-edit.c gnucash-style.c combocell-gnome.c \
|
||||
gnucash-header.c gnucash-item-list.c
|
||||
gnucash-header.c gnucash-item-list.c quickfillcell-gnome.c
|
||||
######################################################################
|
||||
|
||||
default: gnome
|
||||
|
@ -31,6 +31,8 @@
|
||||
own strings.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gnome.h>
|
||||
|
||||
#include "splitreg.h"
|
||||
@ -41,6 +43,7 @@
|
||||
#include "gnucash-item-edit.h"
|
||||
#include "gnucash-item-list.h"
|
||||
#include "global-options.h"
|
||||
#include "messages.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
@ -53,8 +56,10 @@ typedef struct _PopBox
|
||||
GNCItemList *item_list;
|
||||
|
||||
gint select_item_signal;
|
||||
gint change_item_signal;
|
||||
gint key_press_signal;
|
||||
gboolean list_signals_connected;
|
||||
|
||||
gboolean signals_connected; /* list signals connected? */
|
||||
|
||||
gboolean list_in_sync; /* list in sync with menustrings? */
|
||||
gboolean list_sorted; /* list has been sorted? */
|
||||
@ -64,13 +69,21 @@ typedef struct _PopBox
|
||||
gboolean in_list_select;
|
||||
|
||||
gncBoolean strict;
|
||||
|
||||
char complete_char; /* char to be used for auto-completion */
|
||||
|
||||
gchar *ignore_string;
|
||||
gchar *ignore_help;
|
||||
} PopBox;
|
||||
|
||||
|
||||
static void block_list_signals (ComboCell *cell);
|
||||
static void unblock_list_signals (ComboCell *cell);
|
||||
static void realizeCombo (BasicCell *bcell, void *w, int width);
|
||||
static void moveCombo (BasicCell *bcell, int phys_row, int phys_col);
|
||||
static void destroyCombo (BasicCell *bcell);
|
||||
static const char * enterCombo (BasicCell *bcell, const char *value,
|
||||
static const char * enterCombo (BasicCell *bcell,
|
||||
const char *value,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection);
|
||||
@ -101,13 +114,13 @@ void xaccInitComboCell (ComboCell *cell)
|
||||
cell->cell.realize = realizeCombo;
|
||||
cell->cell.destroy = destroyCombo;
|
||||
|
||||
box = g_new(PopBox, 1);
|
||||
box = g_new0(PopBox, 1);
|
||||
|
||||
box->sheet = NULL;
|
||||
box->item_edit = NULL;
|
||||
box->item_list = NULL;
|
||||
box->menustrings = NULL;
|
||||
box->list_signals_connected = FALSE;
|
||||
box->signals_connected = FALSE;
|
||||
box->list_in_sync = TRUE;
|
||||
box->list_sorted = TRUE;
|
||||
box->list_popped = FALSE;
|
||||
@ -118,6 +131,11 @@ void xaccInitComboCell (ComboCell *cell)
|
||||
box->in_list_select = FALSE;
|
||||
|
||||
box->strict = TRUE;
|
||||
|
||||
box->complete_char = 0;
|
||||
|
||||
box->ignore_string = NULL;
|
||||
box->ignore_help = NULL;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
@ -136,6 +154,17 @@ select_item_cb (GNCItemList *item_list, char *item_string, gpointer data)
|
||||
box->list_popped = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
change_item_cb (GNCItemList *item_list, char *item_string, gpointer data)
|
||||
{
|
||||
ComboCell *cell = (ComboCell *) data;
|
||||
PopBox *box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
box->in_list_select = TRUE;
|
||||
gnucash_sheet_modify_current_cell(box->sheet, item_string);
|
||||
box->in_list_select = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
key_press_item_cb (GNCItemList *item_list, GdkEventKey *event, gpointer data)
|
||||
{
|
||||
@ -155,11 +184,11 @@ key_press_item_cb (GNCItemList *item_list, GdkEventKey *event, gpointer data)
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_list_signals (ComboCell *cell)
|
||||
combo_disconnect_signals (ComboCell *cell)
|
||||
{
|
||||
PopBox *box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
if (!box->list_signals_connected)
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list)))
|
||||
@ -168,18 +197,21 @@ disconnect_list_signals (ComboCell *cell)
|
||||
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
|
||||
box->select_item_signal);
|
||||
|
||||
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
|
||||
box->change_item_signal);
|
||||
|
||||
gtk_signal_disconnect(GTK_OBJECT(box->item_list),
|
||||
box->key_press_signal);
|
||||
|
||||
box->list_signals_connected = FALSE;
|
||||
box->signals_connected = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_list_signals (ComboCell *cell)
|
||||
combo_connect_signals (ComboCell *cell)
|
||||
{
|
||||
PopBox *box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
if (box->list_signals_connected)
|
||||
if (box->signals_connected)
|
||||
return;
|
||||
|
||||
if (GTK_OBJECT_DESTROYED(GTK_OBJECT(box->item_list)))
|
||||
@ -190,13 +222,54 @@ connect_list_signals (ComboCell *cell)
|
||||
GTK_SIGNAL_FUNC(select_item_cb),
|
||||
(gpointer) cell);
|
||||
|
||||
box->change_item_signal =
|
||||
gtk_signal_connect(GTK_OBJECT(box->item_list), "change_item",
|
||||
GTK_SIGNAL_FUNC(change_item_cb),
|
||||
(gpointer) cell);
|
||||
|
||||
box->key_press_signal =
|
||||
gtk_signal_connect(GTK_OBJECT(box->item_list),
|
||||
"key_press_event",
|
||||
GTK_SIGNAL_FUNC(key_press_item_cb),
|
||||
(gpointer) cell);
|
||||
|
||||
box->list_signals_connected = TRUE;
|
||||
box->signals_connected = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
block_list_signals (ComboCell *cell)
|
||||
{
|
||||
PopBox *box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
|
||||
box->select_item_signal);
|
||||
|
||||
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
|
||||
box->change_item_signal);
|
||||
|
||||
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
|
||||
box->key_press_signal);
|
||||
}
|
||||
|
||||
static void
|
||||
unblock_list_signals (ComboCell *cell)
|
||||
{
|
||||
PopBox *box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
if (!box->signals_connected)
|
||||
return;
|
||||
|
||||
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
|
||||
box->select_item_signal);
|
||||
|
||||
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
|
||||
box->change_item_signal);
|
||||
|
||||
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
|
||||
box->key_press_signal);
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
@ -210,7 +283,7 @@ destroyCombo (BasicCell *bcell)
|
||||
if (cell->cell.realize == NULL)
|
||||
{
|
||||
if (box != NULL && box->item_list != NULL) {
|
||||
disconnect_list_signals(cell);
|
||||
combo_disconnect_signals(cell);
|
||||
gtk_object_unref(GTK_OBJECT(box->item_list));
|
||||
box->item_list = NULL;
|
||||
}
|
||||
@ -241,6 +314,9 @@ void xaccDestroyComboCell (ComboCell *cell)
|
||||
xaccFreeQuickFill(box->qf);
|
||||
box->qf = NULL;
|
||||
|
||||
g_free(box->ignore_string);
|
||||
g_free(box->ignore_help);
|
||||
|
||||
g_free(box);
|
||||
cell->cell.gui_private = NULL;
|
||||
}
|
||||
@ -276,8 +352,14 @@ xaccClearComboCellMenu (ComboCell * cell)
|
||||
box->qf = xaccMallocQuickFill();
|
||||
|
||||
if (box->item_list != NULL)
|
||||
{
|
||||
block_list_signals(cell);
|
||||
|
||||
gnc_item_list_clear(box->item_list);
|
||||
|
||||
unblock_list_signals(cell);
|
||||
}
|
||||
|
||||
box->list_in_sync = TRUE;
|
||||
box->list_sorted = TRUE;
|
||||
}
|
||||
@ -329,7 +411,15 @@ xaccAddComboCellMenuItem (ComboCell *cell, char * menustr)
|
||||
gnc_combo_sync_edit_list(box);
|
||||
|
||||
if (box->item_list != NULL)
|
||||
{
|
||||
block_list_signals(cell);
|
||||
|
||||
gnc_item_list_append(box->item_list, menustr);
|
||||
if (strcmp(menustr, cell->cell.value) == 0)
|
||||
gnc_item_list_select(box->item_list, menustr);
|
||||
|
||||
unblock_list_signals(cell);
|
||||
}
|
||||
else
|
||||
box->list_in_sync = FALSE;
|
||||
|
||||
@ -357,7 +447,7 @@ ComboMV (BasicCell *_cell,
|
||||
int *start_selection,
|
||||
int *end_selection)
|
||||
{
|
||||
QuickFillCell *cell = (QuickFillCell *) _cell;
|
||||
ComboCell *cell = (ComboCell *) _cell;
|
||||
PopBox *box = cell->cell.gui_private;
|
||||
const char *retval;
|
||||
QuickFill *match;
|
||||
@ -393,7 +483,11 @@ ComboMV (BasicCell *_cell,
|
||||
if ((match == NULL) || (match->text == NULL))
|
||||
{
|
||||
xaccSetBasicCellValue (_cell, newval);
|
||||
|
||||
block_list_signals(cell);
|
||||
gnc_item_list_select(box->item_list, NULL);
|
||||
unblock_list_signals(cell);
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
@ -416,13 +510,9 @@ ComboMV (BasicCell *_cell,
|
||||
box->list_popped = TRUE;
|
||||
}
|
||||
|
||||
gtk_signal_handler_block(GTK_OBJECT(box->item_list),
|
||||
box->select_item_signal);
|
||||
|
||||
block_list_signals(cell);
|
||||
gnc_item_list_select(box->item_list, retval);
|
||||
|
||||
gtk_signal_handler_unblock(GTK_OBJECT(box->item_list),
|
||||
box->select_item_signal);
|
||||
unblock_list_signals(cell);
|
||||
|
||||
xaccSetBasicCellValue (_cell, retval);
|
||||
|
||||
@ -431,6 +521,176 @@ ComboMV (BasicCell *_cell,
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
static gncBoolean
|
||||
ComboDirect (BasicCell *bcell,
|
||||
const char *oldval,
|
||||
char **newval_ptr,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection,
|
||||
void *gui_data)
|
||||
{
|
||||
ComboCell *cell = (ComboCell *) bcell;
|
||||
PopBox *box = cell->cell.gui_private;
|
||||
GdkEventKey *event = gui_data;
|
||||
gboolean keep_on_going = FALSE;
|
||||
gboolean extra_colon;
|
||||
QuickFill *match;
|
||||
char *search;
|
||||
int prefix_len;
|
||||
int new_pos;
|
||||
int length;
|
||||
|
||||
if (event->type != GDK_KEY_PRESS)
|
||||
return GNC_F;
|
||||
|
||||
length = strlen(oldval);
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_slash:
|
||||
if (!(event->state & GDK_MOD1_MASK))
|
||||
{
|
||||
if (event->keyval == box->complete_char)
|
||||
break;
|
||||
|
||||
return GNC_F;
|
||||
}
|
||||
keep_on_going = TRUE;
|
||||
case GDK_Tab:
|
||||
case GDK_ISO_Left_Tab:
|
||||
if (!(event->state & GDK_CONTROL_MASK) &&
|
||||
!keep_on_going)
|
||||
return GNC_F;
|
||||
|
||||
match = xaccGetQuickFillStrLen(box->qf, oldval,
|
||||
*cursor_position);
|
||||
if (match == NULL)
|
||||
return GNC_T;
|
||||
|
||||
match = xaccGetQuickFillUniqueLen(match, &prefix_len);
|
||||
if (match == NULL)
|
||||
return GNC_T;
|
||||
|
||||
if ((match->text != NULL) &&
|
||||
(strncmp(match->text, oldval, length) == 0) &&
|
||||
(strcmp(match->text, oldval) != 0))
|
||||
{
|
||||
*newval_ptr = strdup(match->text);
|
||||
assert(*newval_ptr != NULL);
|
||||
|
||||
xaccSetBasicCellValue(bcell, *newval_ptr);
|
||||
|
||||
block_list_signals(cell);
|
||||
gnc_item_list_select(box->item_list,
|
||||
*newval_ptr);
|
||||
unblock_list_signals(cell);
|
||||
|
||||
}
|
||||
|
||||
*cursor_position += prefix_len;
|
||||
*start_selection = *cursor_position;
|
||||
*end_selection = -1;
|
||||
|
||||
return GNC_T;
|
||||
}
|
||||
|
||||
if (box->complete_char == 0)
|
||||
return GNC_F;
|
||||
|
||||
if (event->keyval != box->complete_char)
|
||||
return GNC_F;
|
||||
|
||||
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
|
||||
return GNC_F;
|
||||
|
||||
if ((*cursor_position < length) &&
|
||||
((*end_selection < length) ||
|
||||
(*cursor_position < *start_selection)))
|
||||
return GNC_F;
|
||||
|
||||
if ((*cursor_position == length) &&
|
||||
(*start_selection != *end_selection) &&
|
||||
(*end_selection < length))
|
||||
return GNC_F;
|
||||
|
||||
search = NULL;
|
||||
if (*cursor_position < length)
|
||||
search = strchr(oldval + *cursor_position + 1,
|
||||
box->complete_char);
|
||||
|
||||
new_pos = *cursor_position;
|
||||
|
||||
if (search != NULL)
|
||||
{
|
||||
new_pos = search - oldval;
|
||||
extra_colon = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_pos = length;
|
||||
extra_colon = TRUE;
|
||||
}
|
||||
|
||||
match = xaccGetQuickFillStrLen(box->qf, oldval, new_pos);
|
||||
if (match == NULL)
|
||||
return GNC_F;
|
||||
|
||||
if (extra_colon)
|
||||
{
|
||||
match = xaccGetQuickFill(match, box->complete_char);
|
||||
if (match == NULL)
|
||||
return GNC_F;
|
||||
|
||||
new_pos++;
|
||||
}
|
||||
|
||||
if ((match->text != NULL) &&
|
||||
(strncmp(match->text, oldval, length) == 0) &&
|
||||
(strcmp(match->text, oldval) != 0))
|
||||
{
|
||||
*newval_ptr = strdup(match->text);
|
||||
assert(*newval_ptr != NULL);
|
||||
|
||||
xaccSetBasicCellValue(bcell, *newval_ptr);
|
||||
|
||||
block_list_signals(cell);
|
||||
gnc_item_list_select(box->item_list, *newval_ptr);
|
||||
unblock_list_signals(cell);
|
||||
}
|
||||
|
||||
*cursor_position = new_pos;
|
||||
*start_selection = new_pos;
|
||||
*end_selection = -1;
|
||||
|
||||
return GNC_T;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
static char *
|
||||
ComboHelpValue(BasicCell *bcell)
|
||||
{
|
||||
ComboCell *cell = (ComboCell *) bcell;
|
||||
PopBox *box = cell->cell.gui_private;
|
||||
|
||||
if ((bcell->value != NULL) && (bcell->value[0] != 0))
|
||||
{
|
||||
if ((box->ignore_string != NULL) &&
|
||||
(box->ignore_help != NULL) &&
|
||||
(safe_strcmp(bcell->value, box->ignore_string) == 0))
|
||||
return strdup(box->ignore_help);
|
||||
|
||||
return strdup(bcell->value);
|
||||
}
|
||||
|
||||
if (bcell->blank_help != NULL)
|
||||
return strdup(bcell->blank_help);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
static void
|
||||
realizeCombo (BasicCell *bcell, void *data, int pixel_width)
|
||||
{
|
||||
@ -454,6 +714,8 @@ realizeCombo (BasicCell *bcell, void *data, int pixel_width)
|
||||
cell->cell.leave_cell = leaveCombo;
|
||||
cell->cell.destroy = destroyCombo;
|
||||
cell->cell.modify_verify = ComboMV;
|
||||
cell->cell.direct_update = ComboDirect;
|
||||
cell->cell.get_help_value = ComboHelpValue;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
@ -463,7 +725,7 @@ moveCombo (BasicCell *bcell, int phys_row, int phys_col)
|
||||
{
|
||||
PopBox *box = (PopBox *) bcell->gui_private;
|
||||
|
||||
disconnect_list_signals((ComboCell *) bcell);
|
||||
combo_disconnect_signals((ComboCell *) bcell);
|
||||
|
||||
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
|
||||
"is_combo", FALSE, NULL);
|
||||
@ -476,13 +738,19 @@ moveCombo (BasicCell *bcell, int phys_row, int phys_col)
|
||||
/* =============================================== */
|
||||
|
||||
static const char *
|
||||
enterCombo (BasicCell *bcell, const char *value,
|
||||
enterCombo (BasicCell *bcell,
|
||||
const char *value,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection)
|
||||
{
|
||||
ComboCell *cell = (ComboCell *) bcell;
|
||||
PopBox *box = (PopBox *) bcell->gui_private;
|
||||
|
||||
if ((box->ignore_string != NULL) &&
|
||||
(safe_strcmp(value, box->ignore_string) == 0))
|
||||
return strdup(value);
|
||||
|
||||
gnc_combo_sync_edit_list(box);
|
||||
gnc_combo_sort_edit_list(box);
|
||||
|
||||
@ -491,9 +759,11 @@ enterCombo (BasicCell *bcell, const char *value,
|
||||
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
|
||||
"is_combo", TRUE, NULL);
|
||||
|
||||
block_list_signals(cell);
|
||||
gnc_item_list_select(box->item_list, bcell->value);
|
||||
unblock_list_signals(cell);
|
||||
|
||||
connect_list_signals((ComboCell *) bcell);
|
||||
combo_connect_signals((ComboCell *) bcell);
|
||||
|
||||
*cursor_position = -1;
|
||||
*start_selection = 0;
|
||||
@ -511,7 +781,7 @@ leaveCombo (BasicCell *bcell, const char *value)
|
||||
|
||||
PopBox *box = (PopBox *) bcell->gui_private;
|
||||
|
||||
disconnect_list_signals((ComboCell *) bcell);
|
||||
combo_disconnect_signals((ComboCell *) bcell);
|
||||
|
||||
gnome_canvas_item_set(GNOME_CANVAS_ITEM(box->item_edit),
|
||||
"is_combo", FALSE, NULL);
|
||||
@ -526,8 +796,10 @@ leaveCombo (BasicCell *bcell, const char *value)
|
||||
(gpointer) value,
|
||||
(GCompareFunc) safe_strcmp);
|
||||
|
||||
/* hack, "Split" is ok, even though it's not in list */
|
||||
if (find == NULL && (safe_strcmp(value, "Split") != 0))
|
||||
/* The ignore string is ok, even if it's not in list. */
|
||||
if (find == NULL &&
|
||||
((box->ignore_string == NULL) ||
|
||||
(safe_strcmp(value, box->ignore_string) != 0)))
|
||||
return strdup("");
|
||||
}
|
||||
|
||||
@ -549,6 +821,51 @@ xaccComboCellSetStrict (ComboCell *cell, gncBoolean strict)
|
||||
box->strict = strict;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
void
|
||||
xaccComboCellSetCompleteChar (ComboCell *cell, char complete_char)
|
||||
{
|
||||
PopBox *box;
|
||||
|
||||
if (cell == NULL)
|
||||
return;
|
||||
|
||||
box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
box->complete_char = complete_char;
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
void
|
||||
xaccComboCellSetIgnoreString (ComboCell *cell, const char *ignore_string)
|
||||
{
|
||||
PopBox *box;
|
||||
|
||||
if (cell == NULL)
|
||||
return;
|
||||
|
||||
box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
box->ignore_string = g_strdup(ignore_string);
|
||||
}
|
||||
|
||||
/* =============================================== */
|
||||
|
||||
void
|
||||
xaccComboCellSetIgnoreHelp (ComboCell *cell, const char *ignore_help)
|
||||
{
|
||||
PopBox *box;
|
||||
|
||||
if (cell == NULL)
|
||||
return;
|
||||
|
||||
box = (PopBox *) cell->cell.gui_private;
|
||||
|
||||
box->ignore_help = g_strdup(ignore_help);
|
||||
}
|
||||
|
||||
/* =============== end of file =================== */
|
||||
|
||||
|
||||
|
@ -254,7 +254,6 @@ draw_cell (GnucashGrid *grid, int block,
|
||||
sheet_block = gnucash_sheet_get_block (grid->sheet, block, 0);
|
||||
|
||||
gdk_gc_set_foreground (grid->gc, sheet_block->bg_colors[i][j]);
|
||||
|
||||
gdk_draw_rectangle (drawable, grid->gc, TRUE, x, y, width, height);
|
||||
|
||||
gdk_gc_set_foreground (grid->gc, &gn_black);
|
||||
@ -269,7 +268,6 @@ draw_cell (GnucashGrid *grid, int block,
|
||||
else
|
||||
font = grid->normal_font;
|
||||
|
||||
gdk_gc_set_foreground (grid->gc, &gn_black);
|
||||
gdk_gc_set_foreground (grid->gc, sheet_block->fg_colors[i][j]);
|
||||
|
||||
if (table->current_cursor_virt_row == block &&
|
||||
|
@ -60,28 +60,35 @@ gnucash_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
|
||||
{
|
||||
GnucashHeader *header = GNUCASH_HEADER(item);
|
||||
SheetBlockStyle *style = header->style;
|
||||
SheetBlockStyle *header_style;
|
||||
int i, j;
|
||||
int xpaint, ypaint;
|
||||
int w = 0, h = 0;
|
||||
gchar *text;
|
||||
GdkFont *font;
|
||||
|
||||
gdk_gc_set_foreground(header->gc, &gn_white);
|
||||
header_style = header->sheet->cursor_style[GNUCASH_CURSOR_HEADER];
|
||||
|
||||
/* Assume all cells have the same color */
|
||||
gdk_gc_set_foreground(header->gc,
|
||||
header_style->inactive_bg_color[0][0]);
|
||||
gdk_draw_rectangle(drawable, header->gc, TRUE, 0, 0, width, height);
|
||||
|
||||
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, -1, -1);
|
||||
gdk_gc_set_foreground (header->gc, &gn_black);
|
||||
gdk_draw_rectangle (drawable, header->gc, FALSE,
|
||||
-x, -y, style->dimensions->width-1, style->dimensions->height);
|
||||
gdk_draw_line (drawable, header->gc,
|
||||
-x, style->dimensions->height-1, style->dimensions->width-1, style->dimensions->height-1);
|
||||
gdk_draw_rectangle (drawable, header->gc, FALSE, -x, -y,
|
||||
style->dimensions->width,
|
||||
style->dimensions->height);
|
||||
gdk_draw_line (drawable, header->gc, -x,
|
||||
style->dimensions->height - 1,
|
||||
style->dimensions->width - 1,
|
||||
style->dimensions->height - 1);
|
||||
|
||||
gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, -1, -1);
|
||||
gdk_gc_set_background (header->gc, &gn_white);
|
||||
gdk_gc_set_foreground (header->gc, &gn_black);
|
||||
font = style->header_font;
|
||||
|
||||
|
||||
ypaint = -y;
|
||||
|
||||
for (i = 0; i < style->nrows; i++) {
|
||||
@ -185,8 +192,13 @@ gnucash_header_unrealize (GnomeCanvasItem *item)
|
||||
header->gc = NULL;
|
||||
}
|
||||
|
||||
if (header->resize_cursor != NULL)
|
||||
gdk_cursor_destroy (header->resize_cursor);
|
||||
header->resize_cursor = NULL;
|
||||
|
||||
if (header->normal_cursor != NULL)
|
||||
gdk_cursor_destroy (header->normal_cursor);
|
||||
header->normal_cursor = NULL;
|
||||
|
||||
if (GNOME_CANVAS_ITEM_CLASS (gnucash_header_parent_class)->unrealize)
|
||||
(*GNOME_CANVAS_ITEM_CLASS
|
||||
@ -200,15 +212,14 @@ gnucash_header_destroy (GtkObject *object)
|
||||
if (GTK_OBJECT_CLASS (gnucash_header_parent_class)->destroy)
|
||||
(*GTK_OBJECT_CLASS
|
||||
(gnucash_header_parent_class)->destroy)(object);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gnucash_header_reconfigure (GnucashHeader *header)
|
||||
{
|
||||
GnomeCanvas *canvas = GNOME_CANVAS_ITEM(header)->canvas;
|
||||
int w, h;
|
||||
double old_w, old_h;
|
||||
int w, h;
|
||||
|
||||
header->style = header->sheet->cursor_style[header->type];
|
||||
|
||||
@ -245,23 +256,30 @@ gnucash_header_point (GnomeCanvasItem *item,
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns -1 if pointer not on a resize line, else returns
|
||||
* the index of the column to the left.
|
||||
* Returns FALSE if pointer not on a resize line, else returns
|
||||
* TRUE. Returns the index of the column to the left in the col
|
||||
* argument.
|
||||
*/
|
||||
static int
|
||||
pointer_on_resize_line (GnucashHeader *header, int x, int y)
|
||||
static gboolean
|
||||
pointer_on_resize_line (GnucashHeader *header, int x, int y, int *col)
|
||||
{
|
||||
SheetBlockStyle *style = header->style;
|
||||
gboolean on_the_line = FALSE;
|
||||
int pixels = 0; /* = style->dimensions->pixel_widths[header->row][0];*/
|
||||
int j;
|
||||
int pixels = style->dimensions->pixel_widths[header->row][0];
|
||||
|
||||
for (j = 1; j < style->ncols; j++) {
|
||||
if (x >= pixels - 1 && x <= pixels+1)
|
||||
return j-1;
|
||||
for (j = 0; j < style->ncols; j++) {
|
||||
pixels += style->dimensions->pixel_widths[header->row][j];
|
||||
if (x >= pixels - 1 && x <= pixels + 1)
|
||||
on_the_line = TRUE;
|
||||
if (x <= pixels + 1)
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (col != NULL)
|
||||
*col = j;
|
||||
|
||||
return on_the_line;
|
||||
}
|
||||
|
||||
|
||||
@ -275,7 +293,8 @@ find_resize_col (GnucashHeader *header, int col)
|
||||
return -1;
|
||||
|
||||
/* skip to the right over zero-width columns */
|
||||
while (col+1 < style->ncols && style->dimensions->pixel_widths[0][col+1] == 0)
|
||||
while (col+1 < style->ncols &&
|
||||
style->dimensions->pixel_widths[0][col+1] == 0)
|
||||
col++;
|
||||
|
||||
/* now go back left till we have a resizable column */
|
||||
@ -290,7 +309,26 @@ find_resize_col (GnucashHeader *header, int col)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_header_auto_resize_column (GnucashHeader *header, gint col)
|
||||
{
|
||||
GnucashSheet *sheet = header->sheet;
|
||||
|
||||
int width = gnucash_sheet_col_max_width (sheet, 0, col);
|
||||
|
||||
gnucash_sheet_style_set_col_width (sheet, header->style,
|
||||
col, width, FALSE);
|
||||
|
||||
gnucash_sheet_style_set_dimensions (sheet, header->style);
|
||||
|
||||
gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
|
||||
item_edit_configure (ITEM_EDIT(sheet->item_editor));
|
||||
|
||||
gnucash_sheet_update_adjustments (sheet);
|
||||
|
||||
gnucash_header_request_redraw (header);
|
||||
gnucash_sheet_redraw_all (sheet);
|
||||
}
|
||||
|
||||
static gint
|
||||
gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
@ -300,7 +338,6 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
int x, y;
|
||||
int col;
|
||||
|
||||
|
||||
switch (event->type) {
|
||||
case GDK_MOTION_NOTIFY:
|
||||
|
||||
@ -331,9 +368,8 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if ((col = pointer_on_resize_line(header, x, y)) > -1 &&
|
||||
gnucash_style_col_is_resizable (header->style, col) )
|
||||
if (pointer_on_resize_line(header, x, y, &col) &&
|
||||
gnucash_style_col_is_resizable (header->style, col))
|
||||
gdk_window_set_cursor (GTK_WIDGET(canvas)->window,
|
||||
header->resize_cursor);
|
||||
else
|
||||
@ -345,11 +381,16 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
{
|
||||
int col;
|
||||
|
||||
if (event->button.button != 1)
|
||||
break;
|
||||
|
||||
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
|
||||
&x, &y);
|
||||
|
||||
col = pointer_on_resize_line (header, x, y);
|
||||
if (pointer_on_resize_line (header, x, y, &col))
|
||||
col = find_resize_col (header, col);
|
||||
else
|
||||
col = -1;
|
||||
|
||||
if (col > -1) {
|
||||
header->in_resize = TRUE;
|
||||
@ -364,6 +405,9 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
{
|
||||
GnucashSheet *sheet = header->sheet;
|
||||
|
||||
if (event->button.button != 1)
|
||||
break;
|
||||
|
||||
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
|
||||
&x, &y);
|
||||
|
||||
@ -371,15 +415,11 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
if (header->needs_ungrab) {
|
||||
gnome_canvas_item_ungrab (item, event->button.time);
|
||||
header->needs_ungrab = FALSE;
|
||||
}
|
||||
|
||||
gnucash_sheet_style_set_col_width (sheet, header->style,
|
||||
header->resize_col, header->resize_col_width, TRUE);
|
||||
header->resize_col, header->resize_col_width, FALSE);
|
||||
gnucash_sheet_style_set_dimensions (sheet, header->style);
|
||||
|
||||
header->in_resize = FALSE;
|
||||
header->resize_col = -1;
|
||||
|
||||
gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
|
||||
item_edit_configure (ITEM_EDIT(sheet->item_editor));
|
||||
|
||||
@ -388,15 +428,47 @@ gnucash_header_event (GnomeCanvasItem *item, GdkEvent *event)
|
||||
gnucash_header_request_redraw (header);
|
||||
gnucash_sheet_redraw_all (sheet);
|
||||
}
|
||||
header->in_resize = FALSE;
|
||||
header->resize_col = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GDK_2BUTTON_PRESS:
|
||||
{
|
||||
gboolean on_line;
|
||||
int ptr_col;
|
||||
int resize_col;
|
||||
|
||||
if (event->button.button != 1)
|
||||
break;
|
||||
|
||||
gnome_canvas_w2c (canvas, event->button.x, event->button.y,
|
||||
&x, &y);
|
||||
|
||||
on_line = pointer_on_resize_line (header, x, y, &ptr_col);
|
||||
resize_col = find_resize_col (header, ptr_col);
|
||||
|
||||
if ((resize_col > -1) &&
|
||||
(on_line || (resize_col == ptr_col))) {
|
||||
header->in_resize = FALSE;
|
||||
header->resize_col = -1;
|
||||
if (header->needs_ungrab) {
|
||||
gnome_canvas_item_ungrab (item, event->button.time);
|
||||
header->needs_ungrab = FALSE;
|
||||
}
|
||||
|
||||
gnucash_header_auto_resize_column (header, resize_col);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -441,7 +513,7 @@ gnucash_header_init (GnucashHeader *header)
|
||||
header->in_resize = FALSE;
|
||||
header->resize_col = -1;
|
||||
header->resize_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
|
||||
header->normal_cursor = gdk_cursor_new (GDK_X_CURSOR);
|
||||
header->normal_cursor = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,7 +28,25 @@
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/* The arguments we take */
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_SHEET, /* The Sheet argument */
|
||||
ARG_GTK_ENTRY, /* The GtkEntry argument */
|
||||
ARG_IS_COMBO, /* Should this be a combo? */
|
||||
};
|
||||
|
||||
/* values for selection info */
|
||||
enum {
|
||||
TARGET_STRING,
|
||||
TARGET_TEXT,
|
||||
TARGET_COMPOUND_TEXT
|
||||
};
|
||||
|
||||
static GnomeCanvasItemClass *item_edit_parent_class;
|
||||
static GdkAtom clipboard_atom = GDK_NONE;
|
||||
static GdkAtom ctext_atom = GDK_NONE;
|
||||
|
||||
|
||||
typedef struct _TextDrawInfo TextDrawInfo;
|
||||
struct _TextDrawInfo
|
||||
@ -63,15 +81,6 @@ struct _TextDrawInfo
|
||||
};
|
||||
|
||||
|
||||
/* The arguments we take */
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_SHEET, /* The Sheet argument */
|
||||
ARG_GTK_ENTRY, /* The GtkEntry argument */
|
||||
ARG_IS_COMBO, /* Should this be a combo? */
|
||||
};
|
||||
|
||||
|
||||
static void item_edit_show_combo_toggle (ItemEdit *item_edit,
|
||||
gint x, gint y,
|
||||
gint width, gint height,
|
||||
@ -364,6 +373,10 @@ item_edit_init (ItemEdit *item_edit)
|
||||
item_edit->editor = NULL;
|
||||
item_edit->clipboard = NULL;
|
||||
|
||||
item_edit->has_selection = FALSE;
|
||||
item_edit->is_combo = FALSE;
|
||||
item_edit->show_list = FALSE;
|
||||
|
||||
item_edit->combo_toggle.combo_button = NULL;
|
||||
item_edit->combo_toggle.combo_button_item = NULL;
|
||||
item_edit->combo_toggle.toggle_offset = 0;
|
||||
@ -393,6 +406,14 @@ queue_sync (ItemEdit *item_edit)
|
||||
gnome_canvas_request_redraw (canvas, x, y, x+w, y+h);
|
||||
}
|
||||
|
||||
void
|
||||
item_edit_redraw (ItemEdit *item_edit)
|
||||
{
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
queue_sync(item_edit);
|
||||
}
|
||||
|
||||
static void
|
||||
entry_changed (GtkEntry *entry, void *data)
|
||||
@ -584,8 +605,42 @@ item_edit_configure (ItemEdit *item_edit)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_claim_selection (ItemEdit *item_edit, guint32 time)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gint start_sel, end_sel;
|
||||
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
editable = GTK_EDITABLE (item_edit->editor);
|
||||
|
||||
start_sel = MIN(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
end_sel = MAX(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
|
||||
if (start_sel != end_sel)
|
||||
{
|
||||
gtk_selection_owner_set (GTK_WIDGET(item_edit->sheet),
|
||||
GDK_SELECTION_PRIMARY, time);
|
||||
item_edit->has_selection = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkWindow *owner;
|
||||
|
||||
owner = gdk_selection_owner_get (GDK_SELECTION_PRIMARY);
|
||||
if (owner == GTK_WIDGET(item_edit->sheet)->window)
|
||||
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
|
||||
item_edit->has_selection = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
|
||||
item_edit_cut_copy_clipboard (ItemEdit *item_edit, guint32 time, gboolean cut)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gint start_sel, end_sel;
|
||||
@ -604,10 +659,14 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
|
||||
if (start_sel == end_sel)
|
||||
return;
|
||||
|
||||
if (item_edit->clipboard != NULL)
|
||||
g_free(item_edit->clipboard);
|
||||
|
||||
clip = gtk_editable_get_chars(editable, start_sel, end_sel);
|
||||
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;
|
||||
|
||||
item_edit->clipboard = clip;
|
||||
|
||||
if (!cut)
|
||||
@ -620,53 +679,44 @@ item_edit_cut_copy_clipboard (ItemEdit *item_edit, gboolean cut)
|
||||
|
||||
|
||||
void
|
||||
item_edit_cut_clipboard (ItemEdit *item_edit)
|
||||
item_edit_cut_clipboard (ItemEdit *item_edit, guint32 time)
|
||||
{
|
||||
item_edit_cut_copy_clipboard(item_edit, TRUE);
|
||||
item_edit_cut_copy_clipboard(item_edit, time, TRUE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_copy_clipboard (ItemEdit *item_edit)
|
||||
item_edit_copy_clipboard (ItemEdit *item_edit, guint32 time)
|
||||
{
|
||||
item_edit_cut_copy_clipboard(item_edit, FALSE);
|
||||
item_edit_cut_copy_clipboard(item_edit, time, FALSE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_paste_clipboard (ItemEdit *item_edit)
|
||||
item_edit_paste_clipboard (ItemEdit *item_edit, guint32 time)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gint start_sel, end_sel;
|
||||
gint current_pos;
|
||||
gchar *clip;
|
||||
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
if ((item_edit->clipboard == NULL) ||
|
||||
(item_edit->clipboard[0] == 0))
|
||||
return;
|
||||
if (ctext_atom == GDK_NONE)
|
||||
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
|
||||
|
||||
editable = GTK_EDITABLE (item_edit->editor);
|
||||
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
|
||||
clipboard_atom, ctext_atom, time);
|
||||
}
|
||||
|
||||
current_pos = editable->current_pos;
|
||||
start_sel = MIN(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
end_sel = MAX(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
|
||||
if (start_sel != end_sel)
|
||||
{
|
||||
gtk_editable_delete_text(editable, start_sel, end_sel);
|
||||
current_pos = start_sel;
|
||||
}
|
||||
void
|
||||
item_edit_paste_primary (ItemEdit *item_edit, guint32 time)
|
||||
{
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
clip = item_edit->clipboard;
|
||||
gtk_editable_insert_text(editable, clip, strlen(clip), ¤t_pos);
|
||||
if (ctext_atom == GDK_NONE)
|
||||
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
|
||||
|
||||
gtk_editable_select_region(editable, 0, 0);
|
||||
gtk_editable_set_position(editable, current_pos);
|
||||
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
|
||||
GDK_SELECTION_PRIMARY, ctext_atom, time);
|
||||
}
|
||||
|
||||
|
||||
@ -871,6 +921,7 @@ item_edit_class_init (ItemEditClass *item_edit_class)
|
||||
item_class->realize = item_edit_realize;
|
||||
}
|
||||
|
||||
|
||||
GtkType
|
||||
item_edit_get_type (void)
|
||||
{
|
||||
@ -921,6 +972,13 @@ create_combo_toggle(GnomeCanvasGroup *parent, ComboToggle *ct)
|
||||
GnomeCanvasItem *
|
||||
item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry)
|
||||
{
|
||||
static const GtkTargetEntry targets[] = {
|
||||
{ "STRING", 0, TARGET_STRING },
|
||||
{ "TEXT", 0, TARGET_TEXT },
|
||||
{ "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
|
||||
};
|
||||
static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
|
||||
|
||||
GnomeCanvasItem *item;
|
||||
ItemEdit *item_edit;
|
||||
|
||||
@ -936,6 +994,17 @@ item_edit_new (GnomeCanvasGroup *parent, GnucashSheet *sheet, GtkWidget *entry)
|
||||
|
||||
create_combo_toggle(parent, &item_edit->combo_toggle);
|
||||
|
||||
if (clipboard_atom == GDK_NONE)
|
||||
clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
|
||||
|
||||
gtk_selection_add_targets (GTK_WIDGET(sheet),
|
||||
GDK_SELECTION_PRIMARY,
|
||||
targets, n_targets);
|
||||
|
||||
gtk_selection_add_targets (GTK_WIDGET(sheet),
|
||||
clipboard_atom,
|
||||
targets, n_targets);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@ -1046,6 +1115,216 @@ item_edit_set_list (ItemEdit *item_edit, GNCItemList *item_list)
|
||||
item_edit_update (GNOME_CANVAS_ITEM(item_edit), NULL, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_set_has_selection (ItemEdit *item_edit, gboolean has_selection)
|
||||
{
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
item_edit->has_selection = has_selection;
|
||||
}
|
||||
|
||||
gboolean
|
||||
item_edit_selection_clear (ItemEdit *item_edit,
|
||||
GdkEventSelection *event)
|
||||
{
|
||||
g_return_val_if_fail(item_edit != NULL, FALSE);
|
||||
g_return_val_if_fail(IS_ITEM_EDIT(item_edit), FALSE);
|
||||
g_return_val_if_fail(event != NULL, FALSE);
|
||||
|
||||
/* Let the selection handling code know that the selection
|
||||
* has been changed, since we've overriden the default handler */
|
||||
if (!gtk_selection_clear(GTK_WIDGET(item_edit->sheet), event))
|
||||
return FALSE;
|
||||
|
||||
if (event->selection == GDK_SELECTION_PRIMARY)
|
||||
{
|
||||
if (item_edit->has_selection)
|
||||
{
|
||||
item_edit->has_selection = FALSE;
|
||||
/* TODO: redraw differently? */
|
||||
}
|
||||
}
|
||||
else if (event->selection == clipboard_atom)
|
||||
{
|
||||
g_free(item_edit->clipboard);
|
||||
item_edit->clipboard = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_selection_get (ItemEdit *item_edit,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
|
||||
gint start_pos;
|
||||
gint end_pos;
|
||||
|
||||
gchar *str;
|
||||
gint length;
|
||||
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
editable = GTK_EDITABLE (item_edit->editor);
|
||||
|
||||
if (selection_data->selection == GDK_SELECTION_PRIMARY)
|
||||
{
|
||||
start_pos = MIN(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
end_pos = MAX(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
|
||||
str = gtk_editable_get_chars(editable, start_pos, end_pos);
|
||||
}
|
||||
else /* CLIPBOARD */
|
||||
str = item_edit->clipboard;
|
||||
|
||||
if (str == NULL)
|
||||
return;
|
||||
|
||||
length = strlen(str);
|
||||
|
||||
if (info == TARGET_STRING)
|
||||
{
|
||||
gtk_selection_data_set (selection_data,
|
||||
GDK_SELECTION_TYPE_STRING,
|
||||
8 * sizeof(gchar), (guchar *) str,
|
||||
length);
|
||||
}
|
||||
else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
|
||||
{
|
||||
guchar *text;
|
||||
gchar c;
|
||||
GdkAtom encoding;
|
||||
gint format;
|
||||
gint new_length;
|
||||
|
||||
c = str[length];
|
||||
str[length] = '\0';
|
||||
|
||||
gdk_string_to_compound_text(str, &encoding, &format,
|
||||
&text, &new_length);
|
||||
|
||||
gtk_selection_data_set(selection_data, encoding,
|
||||
format, text, new_length);
|
||||
|
||||
gdk_free_compound_text(text);
|
||||
|
||||
str[length] = c;
|
||||
}
|
||||
|
||||
if (str != item_edit->clipboard)
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
item_edit_selection_received (ItemEdit *item_edit,
|
||||
GtkSelectionData *selection_data,
|
||||
guint time)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
gboolean reselect;
|
||||
gint old_pos;
|
||||
gint tmp_pos;
|
||||
enum {INVALID, STRING, CTEXT} type;
|
||||
|
||||
g_return_if_fail(item_edit != NULL);
|
||||
g_return_if_fail(IS_ITEM_EDIT(item_edit));
|
||||
|
||||
editable = GTK_EDITABLE(item_edit->editor);
|
||||
|
||||
if (selection_data->type == GDK_TARGET_STRING)
|
||||
type = STRING;
|
||||
else if ((selection_data->type ==
|
||||
gdk_atom_intern("COMPOUND_TEXT", FALSE)) ||
|
||||
(selection_data->type == gdk_atom_intern("TEXT", FALSE)))
|
||||
type = CTEXT;
|
||||
else
|
||||
type = INVALID;
|
||||
|
||||
if (type == INVALID || selection_data->length < 0)
|
||||
{
|
||||
/* avoid infinite loop */
|
||||
if (selection_data->target != GDK_TARGET_STRING)
|
||||
gtk_selection_convert(GTK_WIDGET(item_edit->sheet),
|
||||
selection_data->selection,
|
||||
GDK_TARGET_STRING, time);
|
||||
return;
|
||||
}
|
||||
|
||||
reselect = FALSE;
|
||||
|
||||
if ((editable->selection_start_pos != editable->selection_end_pos) &&
|
||||
(!item_edit->has_selection ||
|
||||
(selection_data->selection == clipboard_atom)))
|
||||
{
|
||||
reselect = TRUE;
|
||||
|
||||
gtk_editable_delete_text(editable,
|
||||
MIN(editable->selection_start_pos,
|
||||
editable->selection_end_pos),
|
||||
MAX(editable->selection_start_pos,
|
||||
editable->selection_end_pos));
|
||||
}
|
||||
|
||||
tmp_pos = old_pos = editable->current_pos;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case STRING:
|
||||
selection_data->data[selection_data->length] = 0;
|
||||
|
||||
gtk_editable_insert_text
|
||||
(editable, (gchar *) selection_data->data,
|
||||
strlen((gchar *)selection_data->data),
|
||||
&tmp_pos);
|
||||
|
||||
gtk_editable_set_position(editable, tmp_pos);
|
||||
break;
|
||||
case CTEXT: {
|
||||
gchar **list;
|
||||
gint count;
|
||||
gint i;
|
||||
|
||||
count = gdk_text_property_to_text_list
|
||||
(selection_data->type, selection_data->format,
|
||||
selection_data->data, selection_data->length,
|
||||
&list);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
gtk_editable_insert_text(editable,
|
||||
list[i],
|
||||
strlen(list[i]),
|
||||
&tmp_pos);
|
||||
|
||||
gtk_editable_set_position(editable, tmp_pos);
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
gdk_free_text_list(list);
|
||||
}
|
||||
break;
|
||||
case INVALID: /* quiet compiler */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reselect)
|
||||
return;
|
||||
|
||||
gtk_editable_select_region(editable, old_pos, editable->current_pos);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 8
|
||||
|
@ -63,6 +63,7 @@ typedef struct
|
||||
guint signal; /* the signal we connect */
|
||||
guint signal2; /* the other signal we connect */
|
||||
|
||||
gboolean has_selection;
|
||||
gboolean is_combo;
|
||||
gboolean show_list;
|
||||
|
||||
@ -101,9 +102,28 @@ gboolean item_edit_set_cursor_pos (ItemEdit *item_edit,
|
||||
gboolean changed_cells,
|
||||
gboolean extend_selection);
|
||||
|
||||
void item_edit_cut_clipboard (ItemEdit *item_edit);
|
||||
void item_edit_copy_clipboard (ItemEdit *item_edit);
|
||||
void item_edit_paste_clipboard (ItemEdit *item_edit);
|
||||
void item_edit_redraw (ItemEdit *item_edit);
|
||||
|
||||
void item_edit_claim_selection (ItemEdit *item_edit, guint32 time);
|
||||
|
||||
void item_edit_cut_clipboard (ItemEdit *item_edit, guint32 time);
|
||||
void item_edit_copy_clipboard (ItemEdit *item_edit, guint32 time);
|
||||
void item_edit_paste_clipboard (ItemEdit *item_edit, guint32 time);
|
||||
void item_edit_paste_primary (ItemEdit *item_edit, guint32 time);
|
||||
|
||||
void item_edit_set_has_selection (ItemEdit *item_edit, gboolean has_selection);
|
||||
|
||||
gboolean item_edit_selection_clear (ItemEdit *item_edit,
|
||||
GdkEventSelection *event);
|
||||
|
||||
void item_edit_selection_get (ItemEdit *item_edit,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time);
|
||||
|
||||
void item_edit_selection_received (ItemEdit *item_edit,
|
||||
GtkSelectionData *selection_data,
|
||||
guint time);
|
||||
|
||||
typedef struct {
|
||||
GnomeCanvasItemClass parent_class;
|
||||
|
@ -28,6 +28,7 @@
|
||||
enum
|
||||
{
|
||||
SELECT_ITEM,
|
||||
CHANGE_ITEM,
|
||||
KEY_PRESS_EVENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -144,19 +145,64 @@ gnc_item_list_button_event(GtkWidget *widget, GdkEventButton *event,
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gnc_clist_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
|
||||
{
|
||||
GtkAdjustment *vadj;
|
||||
gfloat multiplier = 1.0;
|
||||
gfloat v_value;
|
||||
|
||||
vadj = gtk_clist_get_vadjustment(GTK_CLIST(widget));
|
||||
v_value = vadj->value;
|
||||
if (event->state & GDK_SHIFT_MASK)
|
||||
multiplier = 5.0;
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case 4:
|
||||
v_value -= vadj->step_increment * multiplier;
|
||||
break;
|
||||
case 5:
|
||||
v_value += vadj->step_increment * multiplier;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
v_value = CLAMP(v_value, vadj->lower, vadj->upper - vadj->page_size);
|
||||
|
||||
gtk_adjustment_set_value(vadj, v_value);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gnc_item_list_key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||
{
|
||||
GNCItemList *item_list = GNC_ITEM_LIST(data);
|
||||
GtkCList *clist;
|
||||
gboolean got_text;
|
||||
gchar *string;
|
||||
gint row;
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_space:
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
event->state &= ~GDK_CONTROL_MASK;
|
||||
case GDK_Return:
|
||||
clist = item_list->clist;
|
||||
row = clist->focus_row;
|
||||
if (row < 0)
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
got_text = gtk_clist_get_text(clist, row, 0, &string);
|
||||
|
||||
if (!got_text)
|
||||
return FALSE;
|
||||
|
||||
gtk_signal_emit(GTK_OBJECT(item_list),
|
||||
gnc_item_list_signals[SELECT_ITEM],
|
||||
string);
|
||||
|
||||
return TRUE;
|
||||
case GDK_Page_Up:
|
||||
case GDK_Page_Down:
|
||||
case GDK_Up:
|
||||
@ -197,6 +243,16 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
|
||||
GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
|
||||
gnc_item_list_signals[CHANGE_ITEM] =
|
||||
gtk_signal_new("change_item",
|
||||
GTK_RUN_LAST,
|
||||
object_class->type,
|
||||
GTK_SIGNAL_OFFSET(GNCItemListClass,
|
||||
change_item),
|
||||
gtk_marshal_NONE__POINTER,
|
||||
GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
|
||||
gnc_item_list_signals[KEY_PRESS_EVENT] =
|
||||
gtk_signal_new ("key_press_event",
|
||||
GTK_RUN_LAST,
|
||||
@ -210,6 +266,10 @@ gnc_item_list_class_init(GNCItemListClass *item_list_class)
|
||||
gtk_object_class_add_signals(object_class,
|
||||
gnc_item_list_signals,
|
||||
LAST_SIGNAL);
|
||||
|
||||
item_list_class->select_item = NULL;
|
||||
item_list_class->change_item = NULL;
|
||||
item_list_class->key_press_event = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -249,11 +309,15 @@ clist_select_row_cb(GtkCList *clist, gint row, gint column,
|
||||
gboolean got_text;
|
||||
char *string;
|
||||
|
||||
got_text = gtk_clist_get_text(clist, row, column, &string);
|
||||
got_text = gtk_clist_get_text(clist, row, 0, &string);
|
||||
|
||||
if (!got_text)
|
||||
return;
|
||||
|
||||
if (column < 0)
|
||||
gtk_signal_emit(GTK_OBJECT(item_list),
|
||||
gnc_item_list_signals[CHANGE_ITEM], string);
|
||||
else
|
||||
gtk_signal_emit(GTK_OBJECT(item_list),
|
||||
gnc_item_list_signals[SELECT_ITEM], string);
|
||||
}
|
||||
@ -271,6 +335,7 @@ gnc_item_list_new(GnomeCanvasGroup *parent)
|
||||
clist = gtk_clist_new(1);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), clist, TRUE, TRUE, 0);
|
||||
gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
|
||||
gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_BROWSE);
|
||||
|
||||
scrollbar = gtk_vscrollbar_new(NULL);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0);
|
||||
@ -290,7 +355,11 @@ gnc_item_list_new(GnomeCanvasGroup *parent)
|
||||
|
||||
gtk_signal_connect_after(GTK_OBJECT(hbox), "button_press_event",
|
||||
GTK_SIGNAL_FUNC(gnc_item_list_button_event),
|
||||
NULL);
|
||||
(gpointer) item_list);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(clist), "button_press_event",
|
||||
GTK_SIGNAL_FUNC(gnc_clist_button_event),
|
||||
(gpointer) item_list);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(clist), "key_press_event",
|
||||
GTK_SIGNAL_FUNC(gnc_item_list_key_event),
|
||||
|
@ -57,6 +57,9 @@ typedef struct
|
||||
void (*select_item) (GNCItemList *item_list,
|
||||
char *item_string);
|
||||
|
||||
void (*change_item) (GNCItemList *item_list,
|
||||
char *item_string);
|
||||
|
||||
void (*key_press_event) (GNCItemList *item_list,
|
||||
GdkEventKey *event);
|
||||
|
||||
|
@ -36,8 +36,8 @@
|
||||
|
||||
#define DEFAULT_REGISTER_HEIGHT 400
|
||||
#define DEFAULT_REGISTER_WIDTH 630
|
||||
#define DEFAULT_REGISTER_ROWS 15
|
||||
|
||||
static guint gnucash_register_initial_rows = 15;
|
||||
|
||||
static void gnucash_sheet_cell_set_from_table (GnucashSheet *sheet,
|
||||
gint virt_row, gint virt_col,
|
||||
@ -72,6 +72,12 @@ static GtkTableClass *register_parent_class;
|
||||
static guint register_signals[LAST_SIGNAL];
|
||||
|
||||
|
||||
void
|
||||
gnucash_register_set_initial_rows(guint num_rows)
|
||||
{
|
||||
gnucash_register_initial_rows = num_rows;
|
||||
}
|
||||
|
||||
gint
|
||||
gnucash_sheet_cell_valid (GnucashSheet *sheet, gint virt_row, gint virt_col,
|
||||
gint cell_row, gint cell_col)
|
||||
@ -161,7 +167,6 @@ gnucash_sheet_cursor_set_from_table (GnucashSheet *sheet, gncBoolean do_scroll)
|
||||
table->current_cursor_virt_col,
|
||||
cell_row,
|
||||
cell_col);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -393,7 +398,6 @@ gnucash_sheet_block_pixel_origin (GnucashSheet *sheet, gint vrow, gint vcol,
|
||||
|
||||
g_return_if_fail (sheet != NULL);
|
||||
g_return_if_fail (GNUCASH_IS_SHEET(sheet));
|
||||
|
||||
if ( vrow <= 0 || vrow > sheet->num_virt_rows ||
|
||||
vcol < 0 || vcol > sheet->num_virt_cols)
|
||||
return;
|
||||
@ -796,18 +800,18 @@ compute_optimal_width (GnucashSheet *sheet)
|
||||
{
|
||||
SheetBlockStyle *style;
|
||||
|
||||
if (sheet->default_width >= 0)
|
||||
return sheet->default_width;
|
||||
|
||||
if ((sheet == NULL) || (sheet->cursor_style == NULL))
|
||||
return DEFAULT_REGISTER_WIDTH;
|
||||
|
||||
if (sheet->default_width >= 0)
|
||||
return sheet->default_width;
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_HEADER];
|
||||
|
||||
if ((style == NULL) || (style->widths == NULL))
|
||||
return DEFAULT_REGISTER_WIDTH;
|
||||
|
||||
sheet->default_width = gnucash_style_default_width(sheet, style);
|
||||
sheet->default_width = gnucash_style_default_width (sheet, style);
|
||||
|
||||
return sheet->default_width;
|
||||
}
|
||||
@ -832,7 +836,7 @@ compute_optimal_height (GnucashSheet *sheet)
|
||||
return DEFAULT_REGISTER_HEIGHT;
|
||||
|
||||
row_height = style->dimensions->pixel_heights[0][0];
|
||||
sheet->default_height = row_height * DEFAULT_REGISTER_ROWS;
|
||||
sheet->default_height = row_height * gnucash_register_initial_rows;
|
||||
|
||||
return sheet->default_height;
|
||||
}
|
||||
@ -1049,6 +1053,9 @@ gnucash_sheet_delete_cb (GtkWidget *widget,
|
||||
int cursor_position = start_pos;
|
||||
int start_sel, end_sel;
|
||||
|
||||
if (end_pos <= start_pos)
|
||||
return;
|
||||
|
||||
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
|
||||
&p_row, &p_col);
|
||||
gnucash_cursor_get_virt (GNUCASH_CURSOR (sheet->cursor),
|
||||
@ -1179,8 +1186,6 @@ gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
|
||||
sheet);
|
||||
}
|
||||
|
||||
static gboolean dragging = FALSE;
|
||||
|
||||
static gboolean
|
||||
gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
|
||||
{
|
||||
@ -1194,14 +1199,20 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
|
||||
|
||||
sheet = GNUCASH_SHEET(widget);
|
||||
|
||||
if (!dragging || !sheet->editing || event->type != GDK_MOTION_NOTIFY)
|
||||
if (!(event->state & GDK_BUTTON1_MASK) && sheet->grabbed)
|
||||
{
|
||||
gtk_grab_remove (widget);
|
||||
sheet->grabbed = FALSE;
|
||||
}
|
||||
|
||||
if (sheet->button != 1)
|
||||
return FALSE;
|
||||
|
||||
if (!sheet->editing || event->type != GDK_MOTION_NOTIFY)
|
||||
return FALSE;
|
||||
|
||||
if (!(event->state & GDK_BUTTON1_MASK))
|
||||
{
|
||||
dragging = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gnome_canvas_get_scroll_offsets (GNOME_CANVAS(sheet),
|
||||
&xoffset, &yoffset);
|
||||
@ -1221,14 +1232,28 @@ gnucash_motion_event (GtkWidget *widget, GdkEventMotion *event)
|
||||
static gboolean
|
||||
gnucash_button_release_event (GtkWidget *widget, GdkEventButton *event)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
|
||||
g_return_val_if_fail(widget != NULL, TRUE);
|
||||
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), TRUE);
|
||||
g_return_val_if_fail(event != NULL, TRUE);
|
||||
|
||||
sheet = GNUCASH_SHEET (widget);
|
||||
|
||||
if (sheet->button != event->button)
|
||||
return FALSE;
|
||||
|
||||
sheet->button = 0;
|
||||
|
||||
if (event->button != 1)
|
||||
return FALSE;
|
||||
|
||||
dragging = FALSE;
|
||||
gtk_grab_remove (widget);
|
||||
sheet->grabbed = FALSE;
|
||||
|
||||
item_edit_set_has_selection(ITEM_EDIT(sheet->item_editor), FALSE);
|
||||
|
||||
item_edit_claim_selection(ITEM_EDIT(sheet->item_editor), event->time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -1262,6 +1287,25 @@ gnucash_sheet_scroll_event(GnucashSheet *sheet, GdkEventButton *event)
|
||||
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
|
||||
gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
{
|
||||
@ -1286,11 +1330,24 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
sheet = GNUCASH_SHEET (widget);
|
||||
table = sheet->table;
|
||||
|
||||
if (sheet->button && (sheet->button != event->button))
|
||||
return FALSE;
|
||||
|
||||
sheet->button = event->button;
|
||||
|
||||
if (!GTK_WIDGET_HAS_FOCUS(widget))
|
||||
gtk_widget_grab_focus(widget);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
item_edit_paste_primary(ITEM_EDIT(sheet->item_editor),
|
||||
event->time);
|
||||
return TRUE;
|
||||
case 3:
|
||||
return FALSE;
|
||||
case 4:
|
||||
@ -1332,13 +1389,19 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
gtk_editable_set_position(GTK_EDITABLE(sheet->entry), -1);
|
||||
gtk_editable_select_region(GTK_EDITABLE(sheet->entry), 0, -1);
|
||||
|
||||
item_edit_claim_selection (ITEM_EDIT(sheet->item_editor),
|
||||
event->time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
dragging = TRUE;
|
||||
gtk_grab_add(widget);
|
||||
sheet->grabbed = TRUE;
|
||||
|
||||
item_edit_set_has_selection(ITEM_EDIT(sheet->item_editor), TRUE);
|
||||
|
||||
if ((new_p_row == current_p_row) && (new_p_col == current_p_col) &&
|
||||
sheet->editing)
|
||||
@ -1359,11 +1422,18 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
GNC_TABLE_TRAVERSE_POINTER,
|
||||
&new_p_row, &new_p_col);
|
||||
|
||||
gnucash_sheet_check_grab(sheet);
|
||||
|
||||
if (exit_register)
|
||||
return TRUE;
|
||||
|
||||
changed_cells = gnucash_sheet_cursor_move(sheet, new_p_row, new_p_col);
|
||||
|
||||
gnucash_sheet_check_grab(sheet);
|
||||
|
||||
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
|
||||
&new_p_row, &new_p_col);
|
||||
|
||||
item_edit_set_cursor_pos (ITEM_EDIT(sheet->item_editor),
|
||||
new_p_row, new_p_col, x,
|
||||
changed_cells, FALSE);
|
||||
@ -1371,20 +1441,67 @@ gnucash_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gnucash_register_cut_clipboard (GnucashRegister *reg)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
ItemEdit *item_edit;
|
||||
|
||||
g_return_if_fail(reg != NULL);
|
||||
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
|
||||
|
||||
sheet = GNUCASH_SHEET(reg->sheet);
|
||||
item_edit = ITEM_EDIT(sheet->item_editor);
|
||||
|
||||
item_edit_cut_clipboard(item_edit, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
void
|
||||
gnucash_register_copy_clipboard (GnucashRegister *reg)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
ItemEdit *item_edit;
|
||||
|
||||
g_return_if_fail(reg != NULL);
|
||||
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
|
||||
|
||||
sheet = GNUCASH_SHEET(reg->sheet);
|
||||
item_edit = ITEM_EDIT(sheet->item_editor);
|
||||
|
||||
item_edit_copy_clipboard(item_edit, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
void
|
||||
gnucash_register_paste_clipboard (GnucashRegister *reg)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
ItemEdit *item_edit;
|
||||
|
||||
g_return_if_fail(reg != NULL);
|
||||
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
|
||||
|
||||
sheet = GNUCASH_SHEET(reg->sheet);
|
||||
item_edit = ITEM_EDIT(sheet->item_editor);
|
||||
|
||||
item_edit_paste_clipboard(item_edit, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
|
||||
{
|
||||
ItemEdit *item_edit;
|
||||
gboolean handled = FALSE;
|
||||
guint32 time;
|
||||
|
||||
item_edit = ITEM_EDIT(sheet->item_editor);
|
||||
time = event->time;
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_C:
|
||||
case GDK_c:
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
item_edit_copy_clipboard(item_edit);
|
||||
item_edit_copy_clipboard(item_edit, time);
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -1392,7 +1509,7 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
|
||||
case GDK_x:
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
item_edit_cut_clipboard(item_edit);
|
||||
item_edit_cut_clipboard(item_edit, time);
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -1400,19 +1517,19 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
|
||||
case GDK_v:
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
item_edit_paste_clipboard(item_edit);
|
||||
item_edit_paste_clipboard(item_edit, time);
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
case GDK_Insert:
|
||||
if (event->state & GDK_SHIFT_MASK)
|
||||
{
|
||||
item_edit_paste_clipboard(item_edit);
|
||||
item_edit_paste_clipboard(item_edit, time);
|
||||
handled = TRUE;
|
||||
}
|
||||
else if (event->state & GDK_CONTROL_MASK)
|
||||
{
|
||||
item_edit_copy_clipboard(item_edit);
|
||||
item_edit_copy_clipboard(item_edit, time);
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -1421,6 +1538,97 @@ gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
|
||||
return handled;
|
||||
}
|
||||
|
||||
static gncBoolean
|
||||
gnucash_sheet_direct_event(GnucashSheet *sheet, GdkEvent *event)
|
||||
{
|
||||
GtkEditable *editable;
|
||||
Table *table = sheet->table;
|
||||
int v_row, v_col, c_row, c_col;
|
||||
int p_row, p_col;
|
||||
gncBoolean result;
|
||||
gboolean changed;
|
||||
|
||||
const char *old_text;
|
||||
char *new_text;
|
||||
|
||||
int cursor_position, start_sel, end_sel;
|
||||
int new_position, new_start, new_end;
|
||||
|
||||
gnucash_cursor_get_phys(GNUCASH_CURSOR(sheet->cursor), &p_row, &p_col);
|
||||
|
||||
gnucash_cursor_get_virt(GNUCASH_CURSOR(sheet->cursor),
|
||||
&v_row, &v_col, &c_row, &c_col);
|
||||
|
||||
if (!gnc_register_cell_valid (table, p_row, p_col, GNC_T))
|
||||
return GNC_F;
|
||||
|
||||
old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
|
||||
if (old_text == NULL)
|
||||
old_text = "";
|
||||
|
||||
new_text = (char *) old_text;
|
||||
|
||||
editable = GTK_EDITABLE(sheet->entry);
|
||||
|
||||
cursor_position = editable->current_pos;
|
||||
start_sel = MIN(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
end_sel = MAX(editable->selection_start_pos,
|
||||
editable->selection_end_pos);
|
||||
|
||||
new_position = cursor_position;
|
||||
new_start = start_sel;
|
||||
new_end = end_sel;
|
||||
|
||||
result = gnc_table_direct_update(table,
|
||||
p_row, p_col,
|
||||
old_text, &new_text,
|
||||
&new_position,
|
||||
&new_start, &new_end,
|
||||
event);
|
||||
|
||||
gnucash_sheet_cell_set_from_table (sheet, v_row, v_col, c_row, c_col);
|
||||
|
||||
changed = FALSE;
|
||||
|
||||
if ((new_text != old_text) && new_text != NULL)
|
||||
{
|
||||
gtk_signal_handler_block (GTK_OBJECT (sheet->entry),
|
||||
sheet->insert_signal);
|
||||
|
||||
gtk_signal_handler_block (GTK_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
|
||||
gtk_entry_set_text (GTK_ENTRY (sheet->entry), new_text);
|
||||
|
||||
gtk_signal_handler_unblock (GTK_OBJECT (sheet->entry),
|
||||
sheet->delete_signal);
|
||||
|
||||
gtk_signal_handler_unblock (GTK_OBJECT (sheet->entry),
|
||||
sheet->insert_signal);
|
||||
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (new_position != cursor_position)
|
||||
{
|
||||
gtk_editable_set_position (editable, new_position);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if ((new_start != start_sel) || (new_end != end_sel))
|
||||
{
|
||||
gtk_entry_select_region(GTK_ENTRY(sheet->entry),
|
||||
new_start, new_end);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
item_edit_redraw(ITEM_EDIT(sheet->item_editor));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gint
|
||||
gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
{
|
||||
@ -1441,6 +1649,9 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
table = sheet->table;
|
||||
header = table->handlers[0][0];
|
||||
|
||||
if (gnucash_sheet_direct_event(sheet, (GdkEvent *) event))
|
||||
return TRUE;
|
||||
|
||||
gnucash_cursor_get_phys (GNUCASH_CURSOR(sheet->cursor),
|
||||
¤t_p_row, ¤t_p_col);
|
||||
|
||||
@ -1485,7 +1696,7 @@ gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
|
||||
break;
|
||||
case GDK_KP_Down:
|
||||
case GDK_Down:
|
||||
if (event->state & GDK_CONTROL_MASK)
|
||||
if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
|
||||
{
|
||||
ItemEdit *item_edit;
|
||||
|
||||
@ -1830,6 +2041,8 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
|
||||
gint virt_col, gint cell_row, gint cell_col)
|
||||
{
|
||||
SheetBlock *block;
|
||||
SheetBlockStyle *style;
|
||||
|
||||
Table *table;
|
||||
gint p_row, p_col;
|
||||
gchar *text;
|
||||
@ -1841,8 +2054,13 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
|
||||
|
||||
block = gnucash_sheet_get_block (sheet, virt_row, virt_col);
|
||||
|
||||
if (cell_row >= 0 && cell_row <= block->style->nrows
|
||||
&& cell_col >= 0 && cell_col <= block->style->ncols) {
|
||||
style = block->style;
|
||||
|
||||
if (!style)
|
||||
return;
|
||||
|
||||
if (cell_row >= 0 && cell_row <= style->nrows
|
||||
&& cell_col >= 0 && cell_col <= style->ncols) {
|
||||
|
||||
if (block->entries[cell_row][cell_col])
|
||||
g_free (block->entries[cell_row][cell_col]);
|
||||
@ -1859,6 +2077,55 @@ gnucash_sheet_cell_set_from_table (GnucashSheet *sheet, gint virt_row,
|
||||
}
|
||||
|
||||
|
||||
|
||||
gint
|
||||
gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
|
||||
{
|
||||
int virt_row;
|
||||
int cell_row;
|
||||
int max = 0;
|
||||
int width;
|
||||
SheetBlock *block;
|
||||
SheetBlockStyle *style;
|
||||
GdkFont *font;
|
||||
|
||||
g_return_val_if_fail (virt_col >= 0, 0);
|
||||
g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
|
||||
g_return_val_if_fail (cell_col >= 0, 0);
|
||||
|
||||
for (virt_row = 1; virt_row < sheet->num_virt_rows ; virt_row++) {
|
||||
|
||||
block = gnucash_sheet_get_block (sheet, virt_row, virt_col);
|
||||
style = block->style;
|
||||
|
||||
if (!style)
|
||||
continue;
|
||||
|
||||
if (cell_col < style->ncols)
|
||||
for (cell_row = 0; cell_row < style->nrows; cell_row++) {
|
||||
const char *text = gnucash_sheet_block_get_text (sheet,
|
||||
virt_row, virt_col,
|
||||
cell_row, cell_col);
|
||||
|
||||
if (style->fonts[cell_row][cell_col])
|
||||
font = style->fonts[cell_row][cell_col];
|
||||
else
|
||||
font = GNUCASH_GRID(sheet->grid)->normal_font;
|
||||
|
||||
if (!text || strlen(text) == 0) {
|
||||
text = style->labels[cell_row][cell_col];
|
||||
font = style->header_font;
|
||||
}
|
||||
|
||||
width = gdk_string_measure (font, text) + 2*CELL_HPADDING;
|
||||
max = MAX (max, width);
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gnucash_sheet_block_destroy (GnucashSheet *sheet, gint virt_row, gint virt_col)
|
||||
{
|
||||
@ -1968,7 +2235,7 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
|
||||
gnucash_sheet_resize (sheet);
|
||||
|
||||
/* fill it up */
|
||||
for ( i = 0; i < table->num_virt_rows; i++)
|
||||
for (i = 0; i < table->num_virt_rows; i++)
|
||||
for (j = 0; j < table->num_virt_cols; j++)
|
||||
gnucash_sheet_block_set_from_table (sheet, i, j);
|
||||
|
||||
@ -1982,6 +2249,53 @@ gnucash_sheet_table_load (GnucashSheet *sheet)
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gnucash_sheet_selection_clear (GtkWidget *widget,
|
||||
GdkEventSelection *event)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
|
||||
g_return_val_if_fail(widget != NULL, FALSE);
|
||||
g_return_val_if_fail(GNUCASH_IS_SHEET(widget), FALSE);
|
||||
|
||||
sheet = GNUCASH_SHEET(widget);
|
||||
|
||||
return item_edit_selection_clear(ITEM_EDIT(sheet->item_editor), event);
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_selection_get (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
|
||||
g_return_if_fail(widget != NULL);
|
||||
g_return_if_fail(GNUCASH_IS_SHEET(widget));
|
||||
|
||||
sheet = GNUCASH_SHEET(widget);
|
||||
|
||||
item_edit_selection_get(ITEM_EDIT(sheet->item_editor),
|
||||
selection_data, info, time);
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_selection_received (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint time)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
|
||||
g_return_if_fail(widget != NULL);
|
||||
g_return_if_fail(GNUCASH_IS_SHEET(widget));
|
||||
|
||||
sheet = GNUCASH_SHEET(widget);
|
||||
|
||||
item_edit_selection_received(ITEM_EDIT(sheet->item_editor),
|
||||
selection_data, time);
|
||||
}
|
||||
|
||||
static void
|
||||
gnucash_sheet_class_init (GnucashSheetClass *class)
|
||||
{
|
||||
@ -1999,12 +2313,18 @@ gnucash_sheet_class_init (GnucashSheetClass *class)
|
||||
object_class->destroy = gnucash_sheet_destroy;
|
||||
|
||||
widget_class->realize = gnucash_sheet_realize;
|
||||
|
||||
widget_class->size_request = gnucash_sheet_size_request;
|
||||
widget_class->size_allocate = gnucash_sheet_size_allocate;
|
||||
|
||||
widget_class->key_press_event = gnucash_sheet_key_press_event;
|
||||
widget_class->button_press_event = gnucash_button_press_event;
|
||||
widget_class->button_release_event = gnucash_button_release_event;
|
||||
widget_class->motion_notify_event = gnucash_motion_event;
|
||||
|
||||
widget_class->selection_clear_event = gnucash_sheet_selection_clear;
|
||||
widget_class->selection_received = gnucash_sheet_selection_received;
|
||||
widget_class->selection_get = gnucash_sheet_selection_get;
|
||||
}
|
||||
|
||||
|
||||
@ -2053,6 +2373,8 @@ gnucash_sheet_init (GnucashSheet *sheet)
|
||||
sheet->item_editor = NULL;
|
||||
sheet->entry = NULL;
|
||||
sheet->editing = FALSE;
|
||||
sheet->button = 0;
|
||||
sheet->grabbed = FALSE;
|
||||
sheet->default_width = -1;
|
||||
sheet->default_height = -1;
|
||||
sheet->width = 0;
|
||||
@ -2120,7 +2442,6 @@ gnucash_sheet_new (Table *table)
|
||||
sheet->layout_info_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
sheet->dimensions_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
|
||||
/* The cursor */
|
||||
sheet->cursor = gnucash_cursor_new (sheet_group);
|
||||
gnome_canvas_item_set (sheet->cursor,
|
||||
@ -2237,10 +2558,8 @@ gnucash_register_attach_popup(GnucashRegister *reg, GtkWidget *popup,
|
||||
g_return_if_fail(GNUCASH_IS_REGISTER(reg));
|
||||
g_return_if_fail(GTK_IS_WIDGET(popup));
|
||||
g_return_if_fail(reg->sheet != NULL);
|
||||
g_return_if_fail(reg->header_canvas != NULL);
|
||||
|
||||
gnome_popup_menu_attach(popup, reg->sheet, data);
|
||||
gnome_popup_menu_attach(popup, reg->header_canvas, data);
|
||||
}
|
||||
|
||||
|
||||
@ -2297,7 +2616,6 @@ gnucash_register_new (Table *table)
|
||||
reg->hscrollbar = scrollbar;
|
||||
gtk_widget_show(scrollbar);
|
||||
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,9 @@ typedef struct {
|
||||
|
||||
gint editing;
|
||||
|
||||
gint button; /* mouse button being held down */
|
||||
gboolean grabbed; /* has the grab */
|
||||
|
||||
guint insert_signal;
|
||||
guint delete_signal;
|
||||
guint changed_signal;
|
||||
@ -206,6 +209,8 @@ void gnucash_sheet_set_top_block (GnucashSheet *sheet, int new_top_block,
|
||||
|
||||
SheetBlock *gnucash_sheet_get_block (GnucashSheet *sheet, gint vrow,
|
||||
gint vcol);
|
||||
gint
|
||||
gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col);
|
||||
|
||||
gint gnucash_sheet_col_get_distance(GnucashSheet *sheet, int v_row, int col_a, int col_b);
|
||||
|
||||
@ -253,6 +258,12 @@ void gnucash_register_goto_next_virt_row (GnucashRegister *reg);
|
||||
void gnucash_register_attach_popup(GnucashRegister *reg, GtkWidget *popup,
|
||||
gpointer data);
|
||||
|
||||
void gnucash_register_set_initial_rows(guint num_rows);
|
||||
|
||||
void gnucash_register_cut_clipboard (GnucashRegister *reg);
|
||||
void gnucash_register_copy_clipboard (GnucashRegister *reg);
|
||||
void gnucash_register_paste_clipboard (GnucashRegister *reg);
|
||||
|
||||
|
||||
typedef struct {
|
||||
GnomeCanvasClass parent_class;
|
||||
|
@ -277,14 +277,14 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
case GNUCASH_CURSOR_SPLIT:
|
||||
{
|
||||
int i, j;
|
||||
double perc[1][8] = {{0.10, 0.07, 0.15, 0.30, 0.02, 0.12, 0.12, 0.12}};
|
||||
double perc[1][8] = {{0.10, 0.07, 0.25, 0.20, 0.02, 0.12, 0.12, 0.12}};
|
||||
CellLayoutData ld[1][8] =
|
||||
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
|
||||
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 10 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0, 10 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
|
||||
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
}};
|
||||
@ -307,21 +307,21 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
case GNUCASH_CURSOR_DOUBLE:
|
||||
{
|
||||
int i, j;
|
||||
double perc[2][8] = {{0.10, 0.07, 0.15, 0.30, 0.02, 0.12, 0.12, 0.12},
|
||||
{0.10, 0.07, 0.15, 0.68, 0.0, 0.0, 0.0, 0.0}};
|
||||
double perc[2][8] = {{0.10, 0.07, 0.25, 0.20, 0.02, 0.12, 0.12, 0.12},
|
||||
{0.10, 0.07, 0.83, 0.0, 0.0, 0.0, 0.0, 0.0}};
|
||||
CellLayoutData ld[2][8] =
|
||||
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
|
||||
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0,0 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0,0 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
|
||||
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL}},
|
||||
{{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,1,0,1, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,2, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,0,7, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,7, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
@ -359,14 +359,14 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
case GNUCASH_CURSOR_SPLIT:
|
||||
{
|
||||
int i, j;
|
||||
double perc[1][11] = {{0.09, 0.06, 0.11, 0.23, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09}};
|
||||
double perc[1][11] = {{0.09, 0.06, 0.20, 0.14, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09}};
|
||||
CellLayoutData ld[1][11] =
|
||||
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
|
||||
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{STRING_MIN, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
|
||||
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
@ -394,15 +394,15 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
case GNUCASH_CURSOR_DOUBLE:
|
||||
{
|
||||
int i, j;
|
||||
double perc[2][11] = {{0.09, 0.06, 0.11, 0.23, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09},
|
||||
double perc[2][11] = {{0.09, 0.06, 0.20, 0.14, 0.01, 0.10, 0.10, 0.07, 0.07, 0.07, 0.09},
|
||||
{0.0, 0.15, 0.11, 0.74, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
|
||||
CellLayoutData ld[2][11] =
|
||||
{{{STRING_FIXED, RESIZABLE, 0, 0,0,0,0,0,0,0,0,0, 0, 0, date_str},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 3, 0, 5,0,0,0,0,0, 0, 0, NULL},
|
||||
{CHARS_MIN, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{STRING_MIN | FILL, RESIZABLE, 0, 0, 0 ,0, 0 ,0,0,0,0,0, 0, 0, XFRM_STR},
|
||||
{CHARS_MIN | FILL, RESIZABLE, 0, 0,20,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{STRING_FIXED, 0, 1, 0,0,0,0,0,0,0,0,0, 0, 0, "R"},
|
||||
{CHARS_MIN | CHARS_MAX | FILL, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{CHARS_MIN | CHARS_MAX, RESIZABLE, 0, 0, 9,0, 10,0,0,0,0,0, 0, 0, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL},
|
||||
@ -410,8 +410,8 @@ gnucash_style_layout_init (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
{SAME_SIZE, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,5, NULL}},
|
||||
{{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,1,0,1, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,2, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,3,0,10, 0,0, NULL},
|
||||
{LEFT_ALIGNED|RIGHT_ALIGNED, RESIZABLE, 0, 0, 0,0,0,0,0,2,0,10, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
{PIXELS_FIXED, 0, 0, 0, 0,0,0,0,0,0,0,0, 0,0, NULL},
|
||||
@ -724,7 +724,7 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
|
||||
if (layout_info->flags[i][j] & PIXELS_MIN) {
|
||||
int allowed = dimensions->pixel_widths[i][j]
|
||||
- layout_info->pixels_min[i][j];
|
||||
adjustments[j] = MIN (allowed, cellspace);
|
||||
adjustments[j] = MAX(0, MIN (allowed, cellspace));
|
||||
done[j] = (allowed < cellspace);
|
||||
}
|
||||
else adjustments[j] = cellspace;
|
||||
@ -733,8 +733,8 @@ set_dimensions_pass_three (GnucashSheet *sheet, CellLayoutInfo *layout_info,
|
||||
else {
|
||||
if (layout_info->flags[i][j] & PIXELS_MAX) {
|
||||
int allowed = dimensions->pixel_widths[i][j]
|
||||
- layout_info->pixels_min[i][j];
|
||||
adjustments[j] = MAX (allowed, cellspace);
|
||||
- layout_info->pixels_max[i][j];
|
||||
adjustments[j] = MIN(0, MAX (allowed, cellspace));
|
||||
done[j] = (allowed >cellspace);
|
||||
}
|
||||
else adjustments[j] = cellspace;
|
||||
@ -797,16 +797,52 @@ gnucash_style_default_width(GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
{
|
||||
CellLayoutInfo *layout_info;
|
||||
CellDimensions *dimensions;
|
||||
gint width;
|
||||
gint i;
|
||||
|
||||
layout_info = style->layout_info;
|
||||
dimensions = style->dimensions;
|
||||
|
||||
dimensions->height = 0;
|
||||
width = dimensions->width = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
return compute_row_width(dimensions, 0, 0, layout_info->ncols);
|
||||
width = compute_row_width(dimensions, 0, 0,
|
||||
layout_info->ncols - 1);
|
||||
|
||||
dimensions->width = width;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
gnucash_style_row_width(SheetBlockStyle *style, int row)
|
||||
{
|
||||
CellLayoutInfo *layout_info;
|
||||
CellDimensions *dimensions;
|
||||
|
||||
layout_info = style->layout_info;
|
||||
dimensions = style->dimensions;
|
||||
|
||||
return compute_row_width(dimensions, row, 0, layout_info->ncols - 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
compute_cell_origins_x (CellDimensions *dimensions, int row)
|
||||
{
|
||||
@ -894,7 +930,8 @@ gnucash_sheet_style_set_dimensions (GnucashSheet *sheet,
|
||||
g_return_if_fail (GNUCASH_IS_SHEET (sheet));
|
||||
g_return_if_fail (style != NULL);
|
||||
|
||||
style_recompute_layout_dimensions (sheet, style->layout_info, style->dimensions);
|
||||
style_recompute_layout_dimensions (sheet, style->layout_info,
|
||||
style->dimensions);
|
||||
}
|
||||
|
||||
gint
|
||||
@ -907,8 +944,8 @@ gnucash_style_col_is_resizable (SheetBlockStyle *style, int col)
|
||||
}
|
||||
|
||||
/*
|
||||
* Set width of a specified cell and set the PIXEL_FIXED flag. If
|
||||
* same_size is TRUE, also set the width of any
|
||||
* Set width of a specified cell and set the PIXEL_FIXED flag.
|
||||
* If same_size is TRUE, also set the width of any
|
||||
* SAME_SIZE cell which references this one. Otherwise those
|
||||
* cells are set to PIXELS_FIXED with their current width.
|
||||
*/
|
||||
@ -925,18 +962,12 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
|
||||
|
||||
if (width >= 0) {
|
||||
|
||||
#if 0
|
||||
if (style->dimensions->pixel_widths[0][col] > width) {
|
||||
style->layout_info->pixels_max[0][col] = width;
|
||||
style->layout_info->flags[0][col] = PIXELS_MAX;
|
||||
}
|
||||
else {
|
||||
style->layout_info->pixels_min[0][col] = width;
|
||||
style->layout_info->flags[0][col] = PIXELS_MIN;
|
||||
}
|
||||
#endif
|
||||
style->layout_info->flags[0][col] = PIXELS_FIXED;
|
||||
style->layout_info->pixels_width[0][col] = width;
|
||||
/* Note that we may want to preserve the FILL flag on
|
||||
* this, but for now let's leave it off.
|
||||
* style->layout_info->flags[0][col] = PIXELS_FIXED |
|
||||
* (style->layout_info->flags[0][col] & FILL); */
|
||||
style->layout_info->flags[0][col] = PIXELS_FIXED;
|
||||
style->dimensions->pixel_widths[0][col] = width;
|
||||
|
||||
for (i = 0; i < style->nrows; i++) {
|
||||
@ -947,7 +978,12 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
|
||||
if (same_size)
|
||||
style->dimensions->pixel_widths[i][j] = width;
|
||||
else
|
||||
{
|
||||
style->layout_info->flags[i][j] = PIXELS_FIXED;
|
||||
style->layout_info->pixels_width[i][j] =
|
||||
style->dimensions->pixel_widths[i][j];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -961,8 +997,6 @@ gnucash_sheet_style_set_col_width (GnucashSheet *sheet, SheetBlockStyle *style,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
{
|
||||
@ -991,14 +1025,16 @@ gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
style->layout_info->refcount--;
|
||||
|
||||
if (style->layout_info->refcount == 0) {
|
||||
g_hash_table_remove (sheet->layout_info_hash_table, style_get_key (style));
|
||||
g_hash_table_remove (sheet->layout_info_hash_table,
|
||||
style_get_key (style));
|
||||
style_layout_info_destroy (style->layout_info);
|
||||
}
|
||||
|
||||
style->dimensions->refcount--;
|
||||
|
||||
if (style->dimensions->refcount == 0) {
|
||||
g_hash_table_remove (sheet->dimensions_hash_table, style_get_key (style));
|
||||
g_hash_table_remove (sheet->dimensions_hash_table,
|
||||
style_get_key (style));
|
||||
style_dimensions_destroy (style->dimensions);
|
||||
}
|
||||
|
||||
@ -1006,13 +1042,71 @@ gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
|
||||
}
|
||||
|
||||
|
||||
/* Recompiles the style information from the cellblock, without
|
||||
* recomputing the layout info or the dimensions. WARNING: this
|
||||
* function assumes that the space for the style info has been
|
||||
* allocated already. */
|
||||
void
|
||||
gnucash_sheet_style_recompile(SheetBlockStyle *style, CellBlock *cellblock,
|
||||
SplitRegister *sr, gint cursor_type)
|
||||
{
|
||||
gint i, j, type;
|
||||
char *label;
|
||||
|
||||
for (i = 0; i < style->nrows; i++)
|
||||
for (j = 0; j < style->ncols; j++) {
|
||||
type = cellblock->cell_types[i][j];
|
||||
|
||||
style->widths[i][j] = cellblock->widths[j];
|
||||
|
||||
style->fonts[i][j] = NULL;
|
||||
style->header_font = gnucash_default_font;
|
||||
|
||||
if (type > -1)
|
||||
label = sr->header_label_cells[type]->value;
|
||||
else if (cursor_type == GNUCASH_CURSOR_HEADER)
|
||||
label = cellblock->cells[i][j]->value;
|
||||
else
|
||||
label = "";
|
||||
|
||||
g_free(style->labels[i][j]);
|
||||
style->labels[i][j] = g_strdup(label);
|
||||
|
||||
style->active_bg_color[i][j] =
|
||||
gnucash_color_argb_to_gdk
|
||||
(cellblock->active_bg_color);
|
||||
|
||||
style->inactive_bg_color[i][j] =
|
||||
gnucash_color_argb_to_gdk
|
||||
(cellblock->passive_bg_color);
|
||||
|
||||
switch (cellblock->alignments[j]) {
|
||||
case ALIGN_RIGHT:
|
||||
style->alignments[i][j] =
|
||||
GTK_JUSTIFY_RIGHT;
|
||||
break;
|
||||
case ALIGN_CENTER:
|
||||
style->alignments[i][j] =
|
||||
GTK_JUSTIFY_CENTER;
|
||||
break;
|
||||
default:
|
||||
case ALIGN_FILL:
|
||||
case ALIGN_LEFT:
|
||||
style->alignments[i][j] =
|
||||
GTK_JUSTIFY_LEFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SheetBlockStyle *
|
||||
gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
|
||||
gint cursor_type)
|
||||
{
|
||||
gint i, j;
|
||||
SheetBlockStyle *style;
|
||||
SplitRegister *sr;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (sheet != NULL, NULL);
|
||||
g_return_val_if_fail (GNUCASH_IS_SHEET (sheet), NULL);
|
||||
@ -1045,42 +1139,7 @@ gnucash_sheet_style_compile (GnucashSheet *sheet, CellBlock *cellblock,
|
||||
style->labels[i] = g_new0 (char *, style->ncols);
|
||||
}
|
||||
|
||||
for (i = 0; i < style->nrows; i++)
|
||||
for (j = 0; j < style->ncols; j++) {
|
||||
gint type = cellblock->cell_types[i][j];
|
||||
char *label;
|
||||
|
||||
style->widths[i][j] = cellblock->widths[j];
|
||||
|
||||
style->fonts[i][j] = NULL;
|
||||
style->header_font = gnucash_default_font;
|
||||
|
||||
if (type > -1)
|
||||
label = sr->header_label_cells[type]->value;
|
||||
else if (cursor_type == GNUCASH_CURSOR_HEADER)
|
||||
label = cellblock->cells[i][j]->value;
|
||||
else
|
||||
label = "";
|
||||
|
||||
style->labels[i][j] = g_strdup(label);
|
||||
|
||||
style->active_bg_color[i][j] = gnucash_color_argb_to_gdk (cellblock->active_bg_color);
|
||||
style->inactive_bg_color[i][j] = gnucash_color_argb_to_gdk (cellblock->passive_bg_color);
|
||||
|
||||
switch (cellblock->alignments[j]) {
|
||||
case ALIGN_RIGHT:
|
||||
style->alignments[i][j] = GTK_JUSTIFY_RIGHT;
|
||||
break;
|
||||
case ALIGN_CENTER:
|
||||
style->alignments[i][j] = GTK_JUSTIFY_CENTER;
|
||||
break;
|
||||
default:
|
||||
case ALIGN_FILL:
|
||||
case ALIGN_LEFT:
|
||||
style->alignments[i][j] = GTK_JUSTIFY_LEFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gnucash_sheet_style_recompile(style, cellblock, sr, cursor_type);
|
||||
|
||||
gnucash_style_layout_init (sheet, style);
|
||||
gnucash_style_dimensions_init (sheet, style);
|
||||
|
@ -34,6 +34,8 @@ void gnucash_sheet_style_set_col_width (GnucashSheet *sheet,
|
||||
|
||||
gint gnucash_style_default_width(GnucashSheet *sheet, SheetBlockStyle *style);
|
||||
|
||||
gint gnucash_style_row_width(SheetBlockStyle *style, int row);
|
||||
|
||||
void gnucash_sheet_style_set_dimensions (GnucashSheet *sheet,
|
||||
SheetBlockStyle *style);
|
||||
|
||||
@ -43,6 +45,11 @@ SheetBlockStyle * gnucash_sheet_style_compile (GnucashSheet *sheet,
|
||||
CellBlock *cellblock,
|
||||
gint cursor_type);
|
||||
|
||||
void gnucash_sheet_style_recompile (SheetBlockStyle *style,
|
||||
CellBlock *cellblock,
|
||||
SplitRegister *sr,
|
||||
gint cursor_type);
|
||||
|
||||
SheetBlockStyle *gnucash_sheet_get_style (GnucashSheet *sheet, gint vrow,
|
||||
gint vcol);
|
||||
|
||||
|
101
src/register/gnome/quickfillcell-gnome.c
Normal file
101
src/register/gnome/quickfillcell-gnome.c
Normal 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:
|
||||
*/
|
@ -38,7 +38,7 @@
|
||||
static void PriceSetValue (BasicCell *, const char *);
|
||||
static char * xaccPriceCellPrintValue (PriceCell *cell);
|
||||
|
||||
/* set the color of the text to red, if teh value is negative */
|
||||
/* set the color of the text to red, if the value is negative */
|
||||
/* hack alert -- the actual color should probably be configurable */
|
||||
#define COLORIZE(cell,amt) { \
|
||||
if (0.0 > amt) { \
|
||||
@ -79,7 +79,7 @@ PriceEnter (BasicCell *_cell,
|
||||
|
||||
static const char *
|
||||
PriceMV (BasicCell *_cell,
|
||||
const char * oldval,
|
||||
const char *oldval,
|
||||
const char *change,
|
||||
const char *newval,
|
||||
int *cursor_position,
|
||||
@ -96,18 +96,25 @@ PriceMV (BasicCell *_cell,
|
||||
decimal_point = lc->decimal_point[0];
|
||||
|
||||
/* accept the newval string if user action was delete, etc. */
|
||||
if (change) {
|
||||
/* if change is a decimal point, then count decimal points */
|
||||
if (decimal_point == change[0]) {
|
||||
if (change != NULL)
|
||||
{
|
||||
int i, count=0;
|
||||
for (i=0; 0 != newval[i]; i++) {
|
||||
if (decimal_point == newval[i]) count ++;
|
||||
|
||||
for (i=0; 0 != change[i]; i++)
|
||||
{
|
||||
/* accept only numbers or a decimal point */
|
||||
if (!isdigit(change[i]) && (decimal_point != change[i]))
|
||||
return NULL;
|
||||
|
||||
if (decimal_point == change[i])
|
||||
count++;
|
||||
}
|
||||
|
||||
for (i=0; 0 != oldval[i]; i++)
|
||||
if (decimal_point == oldval[i])
|
||||
count++;
|
||||
|
||||
if (1 < count) return NULL;
|
||||
} else {
|
||||
/* accept numeric, reject non-alpha edits */
|
||||
if (! (isdigit (change[0]))) return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse the float pt value and store it */
|
||||
@ -131,11 +138,34 @@ PriceLeave (BasicCell *_cell, const char *val)
|
||||
return val;
|
||||
|
||||
/* Otherwise, return the new one. */
|
||||
SET ((&(cell->cell)), newval);
|
||||
return strdup(newval);
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
static char *
|
||||
PriceHelp(BasicCell *bcell)
|
||||
{
|
||||
PriceCell *cell = (PriceCell *) bcell;
|
||||
|
||||
if ((bcell->value != NULL) && (bcell->value[0] != 0))
|
||||
{
|
||||
char *help_str;
|
||||
|
||||
help_str = xaccPriceCellPrintValue(cell);
|
||||
|
||||
return strdup(help_str);
|
||||
}
|
||||
|
||||
if (bcell->blank_help != NULL)
|
||||
return strdup(bcell->blank_help);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
PriceCell *
|
||||
xaccMallocPriceCell (void)
|
||||
{
|
||||
@ -153,8 +183,9 @@ xaccInitPriceCell (PriceCell *cell)
|
||||
xaccInitBasicCell( &(cell->cell));
|
||||
|
||||
cell->amount = 0.0;
|
||||
cell->blank_zero = 1;
|
||||
cell->prt_format = strdup ("%m");
|
||||
cell->precision = 2;
|
||||
cell->blank_zero = GNC_T;
|
||||
cell->min_trail_zeros = 2;
|
||||
cell->monetary = GNC_T;
|
||||
|
||||
SET ( &(cell->cell), "");
|
||||
@ -164,6 +195,7 @@ xaccInitPriceCell (PriceCell *cell)
|
||||
cell->cell.modify_verify = PriceMV;
|
||||
cell->cell.leave_cell = PriceLeave;
|
||||
cell->cell.set_value = PriceSetValue;
|
||||
cell->cell.get_help_value = PriceHelp;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
@ -172,7 +204,6 @@ void
|
||||
xaccDestroyPriceCell (PriceCell *cell)
|
||||
{
|
||||
cell->amount = 0.0;
|
||||
free (cell->prt_format); cell->prt_format = 0x0;
|
||||
xaccDestroyBasicCell ( &(cell->cell));
|
||||
}
|
||||
|
||||
@ -182,34 +213,26 @@ static char *
|
||||
xaccPriceCellPrintValue (PriceCell *cell)
|
||||
{
|
||||
static char buff[PRTBUF];
|
||||
char tmpfmt[PRTBUF];
|
||||
char tmpval[PRTBUF];
|
||||
char *monet;
|
||||
|
||||
if (cell->blank_zero && DEQ(cell->amount, 0.0)) {
|
||||
strcpy(buff, "");
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* check for monetary-style format not natively supported by printf */
|
||||
/* hack alert -- this type of extended function should be abstracted
|
||||
* out to a gnc_sprintf type function, however, this is much
|
||||
* easier said than done */
|
||||
monet = strstr (cell->prt_format, "%m");
|
||||
if (monet) {
|
||||
strcpy (tmpfmt, cell->prt_format);
|
||||
monet = strstr (tmpfmt, "%m");
|
||||
*(monet+1) = 's';
|
||||
xaccSPrintAmount (tmpval, cell->amount, PRTSEP);
|
||||
snprintf (buff, PRTBUF, tmpfmt, tmpval);
|
||||
} else {
|
||||
snprintf (buff, PRTBUF, cell->prt_format, cell->amount);
|
||||
}
|
||||
xaccSPrintAmountGeneral(buff, cell->amount, PRTSEP, cell->precision,
|
||||
cell->monetary, cell->min_trail_zeros);
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
double
|
||||
xaccGetPriceCellValue (PriceCell *cell)
|
||||
{
|
||||
assert(cell != NULL);
|
||||
|
||||
return cell->amount;
|
||||
}
|
||||
|
||||
void xaccSetPriceCellValue (PriceCell * cell, double amt)
|
||||
{
|
||||
@ -226,13 +249,12 @@ void xaccSetPriceCellValue (PriceCell * cell, double amt)
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
void xaccSetPriceCellFormat (PriceCell * cell, char * fmt)
|
||||
void
|
||||
xaccSetPriceCellPrecision (PriceCell *cell, int precision)
|
||||
{
|
||||
if (cell->prt_format) free (cell->prt_format);
|
||||
cell->prt_format = strdup (fmt);
|
||||
assert(cell != NULL);
|
||||
|
||||
/* make sure that the cell is updated with the new format */
|
||||
xaccSetPriceCellValue (cell, cell->amount);
|
||||
cell->precision = precision;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
@ -240,11 +262,33 @@ void xaccSetPriceCellFormat (PriceCell * cell, char * fmt)
|
||||
void
|
||||
xaccSetPriceCellMonetary (PriceCell * cell, gncBoolean monetary)
|
||||
{
|
||||
assert(cell != NULL);
|
||||
|
||||
cell->monetary = monetary;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
void
|
||||
xaccSetPriceCellMinTrailZeros (PriceCell * cell, int min_trail_zeros)
|
||||
{
|
||||
assert(cell != NULL);
|
||||
|
||||
cell->min_trail_zeros = min_trail_zeros;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
void
|
||||
xaccSetPriceCellBlankZero (PriceCell *cell, gncBoolean blank_zero)
|
||||
{
|
||||
assert(cell != NULL);
|
||||
|
||||
cell->blank_zero = blank_zero;
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
void xaccSetDebCredCellValue (PriceCell * deb,
|
||||
PriceCell * cred, double amt)
|
||||
{
|
||||
|
@ -53,11 +53,16 @@
|
||||
#include "basiccell.h"
|
||||
#include "gnc-common.h"
|
||||
|
||||
typedef struct _PriceCell {
|
||||
typedef struct _PriceCell
|
||||
{
|
||||
BasicCell cell;
|
||||
|
||||
double amount; /* the amount associated with this cell */
|
||||
short blank_zero; /* controls printing of zero values */
|
||||
char *prt_format; /* controls display of value; printf format */
|
||||
|
||||
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;
|
||||
|
||||
@ -66,17 +71,22 @@ PriceCell * xaccMallocPriceCell (void);
|
||||
void xaccInitPriceCell (PriceCell *);
|
||||
void xaccDestroyPriceCell (PriceCell *);
|
||||
|
||||
/* updates amount, string format is three decimal places */
|
||||
void xaccSetPriceCellValue (PriceCell *, double amount);
|
||||
/* return the value of a price cell */
|
||||
double xaccGetPriceCellValue (PriceCell *cell);
|
||||
|
||||
/* The xaccSetPriceCellFormat() method is used to control how
|
||||
* the cell contents are displayed. It accepts as an argument
|
||||
* a printf-style format. The format must control the display
|
||||
* of a double-precision float. See the printf() command for
|
||||
* allowed syntax. The default format is "%m" for a monetary
|
||||
* style format.
|
||||
*/
|
||||
void xaccSetPriceCellFormat (PriceCell *, char * fmt);
|
||||
/* updates amount, string format is three decimal places */
|
||||
void xaccSetPriceCellValue (PriceCell *cell, double amount);
|
||||
|
||||
/* sets the precision of the printed value. Defaults to 2 */
|
||||
void xaccSetPriceCellPrecision (PriceCell *cell, int precision);
|
||||
|
||||
/* Sets the mininum number of trailing decimal zeros that must
|
||||
* be printed. Defaults to 2. */
|
||||
void xaccSetPriceCellMinTrailZeros (PriceCell *cell, int);
|
||||
|
||||
/* determines whether 0 values are left blank or printed.
|
||||
* defaults to true. */
|
||||
void xaccSetPriceCellBlankZero (PriceCell *cell, gncBoolean);
|
||||
|
||||
/* The xaccSetPriceCellMonetary() sets a flag which determines
|
||||
* how string amounts are parsed, either as monetary or
|
||||
|
29
src/register/quickfillcell-motif.c
Normal file
29
src/register/quickfillcell-motif.c
Normal 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 */
|
||||
}
|
@ -257,6 +257,8 @@ xaccInitQuickFillCell (QuickFillCell *cell)
|
||||
cell->cell.modify_verify = quick_modify;
|
||||
cell->cell.leave_cell = quick_leave;
|
||||
cell->cell.set_value = quick_set;
|
||||
|
||||
xaccQuickFillGUIInit (cell);
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
@ -61,6 +61,9 @@ void xaccDestroyQuickFillCell (QuickFillCell *);
|
||||
void xaccSetQuickFillCellValue (QuickFillCell *, const char *);
|
||||
void xaccSetQuickFillSort (QuickFillCell *, QuickFillSort);
|
||||
|
||||
/* GUI-dependent */
|
||||
void xaccQuickFillGUIInit (QuickFillCell *);
|
||||
|
||||
#endif /* __XACC_FILL_CELL_C__ */
|
||||
|
||||
/* --------------- end of file ---------------------- */
|
||||
|
@ -43,6 +43,27 @@
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static short module = MOD_REGISTER;
|
||||
|
||||
static SplitRegisterColors reg_colors = {
|
||||
0xffdddd, /* pale red, single cursor active */
|
||||
0xccccff, /* pale blue, single cursor passive */
|
||||
0xccccff, /* pale blue, single cursor passive 2 */
|
||||
|
||||
0xffdddd, /* pale red, double cursor active */
|
||||
0xccccff, /* pale blue, double cursor passive */
|
||||
0xffffff, /* white, double cursor passive 2 */
|
||||
|
||||
GNC_F, /* double mode alternate by physical row */
|
||||
|
||||
0xffdddd, /* pale red, trans cursor active */
|
||||
0xccccff, /* pale blue, trans cursor passive */
|
||||
|
||||
0xffffdd, /* pale yellow, split cursor active */
|
||||
0xffffff, /* white, split cursor passive */
|
||||
|
||||
0xffffff /* white, header color */
|
||||
};
|
||||
|
||||
|
||||
/* utility defines for cell configuration data */
|
||||
#define DATE_CELL 0
|
||||
#define NUM_CELL 1
|
||||
@ -89,9 +110,9 @@ static short module = MOD_REGISTER;
|
||||
#define DATE_CELL_ALIGN ALIGN_RIGHT
|
||||
#define NUM_CELL_ALIGN ALIGN_LEFT
|
||||
#define ACTN_CELL_ALIGN ALIGN_LEFT
|
||||
#define XFRM_CELL_ALIGN ALIGN_LEFT
|
||||
#define MXFRM_CELL_ALIGN ALIGN_LEFT
|
||||
#define XTO_CELL_ALIGN ALIGN_LEFT
|
||||
#define XFRM_CELL_ALIGN ALIGN_RIGHT
|
||||
#define MXFRM_CELL_ALIGN ALIGN_RIGHT
|
||||
#define XTO_CELL_ALIGN ALIGN_RIGHT
|
||||
#define DESC_CELL_ALIGN ALIGN_LEFT
|
||||
#define MEMO_CELL_ALIGN ALIGN_LEFT
|
||||
#define RECN_CELL_ALIGN ALIGN_CENTER
|
||||
@ -104,14 +125,7 @@ static short module = MOD_REGISTER;
|
||||
#define SHRS_CELL_ALIGN ALIGN_RIGHT
|
||||
#define BALN_CELL_ALIGN ALIGN_RIGHT
|
||||
|
||||
/* Use 4 decimal places for everything that isn't a $ value
|
||||
* Perhaps this should be changed to store precision selection
|
||||
* in a config file. */
|
||||
#define SHRS_CELL_FORMAT "%0.4f"
|
||||
#define DEBIT_CELL_FORMAT "%0.4f"
|
||||
#define CREDIT_CELL_FORMAT "%0.4f"
|
||||
#define PRICE_CELL_FORMAT "%0.4f"
|
||||
|
||||
#define SHARES_PRECISION 4
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
@ -357,27 +371,29 @@ configLayout (SplitRegister *reg)
|
||||
curs = reg->double_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
FANCY (MXFRM, mxfrm, 3, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
FANCY (BALN, balance, 7, 0);
|
||||
|
||||
FANCY (ACTN, action, 1, 1);
|
||||
FANCY (MXFRM, mxfrm, 2, 1);
|
||||
BASIC (MEMO, memo, 3, 1);
|
||||
FANCY (MEMO, memo, 2, 1);
|
||||
|
||||
curs = reg->trans_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
FANCY (BALN, balance, 7, 0);
|
||||
|
||||
curs = reg->split_cursor;
|
||||
FANCY (ACTN, action, 1, 0);
|
||||
FANCY (XFRM, xfrm, 2, 0);
|
||||
BASIC (MEMO, memo, 3, 0);
|
||||
FANCY (MEMO, memo, 2, 0);
|
||||
FANCY (XFRM, xfrm, 3, 0);
|
||||
FANCY (NDEBT, ndebit, 5, 0);
|
||||
FANCY (NCRED, ncredit, 6, 0);
|
||||
|
||||
@ -385,8 +401,8 @@ configLayout (SplitRegister *reg)
|
||||
curs = reg->single_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (MXFRM, mxfrm, 2, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
FANCY (MXFRM, mxfrm, 3, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
@ -404,7 +420,8 @@ configLayout (SplitRegister *reg)
|
||||
curs = reg->double_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
FANCY (MXFRM, mxfrm, 3, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
@ -414,14 +431,13 @@ configLayout (SplitRegister *reg)
|
||||
FANCY (BALN, balance, 10, 0);
|
||||
|
||||
FANCY (ACTN, action, 1, 1);
|
||||
FANCY (MXFRM, mxfrm, 2, 1);
|
||||
BASIC (MEMO, memo, 3, 1);
|
||||
FANCY (MEMO, memo, 2, 1);
|
||||
|
||||
/* only the transaction cursor gets used */
|
||||
curs = reg->trans_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
@ -432,8 +448,8 @@ configLayout (SplitRegister *reg)
|
||||
|
||||
curs = reg->split_cursor;
|
||||
FANCY (ACTN, action, 1, 0);
|
||||
FANCY (XFRM, xfrm, 2, 0);
|
||||
BASIC (MEMO, memo, 3, 0);
|
||||
FANCY (MEMO, memo, 2, 0);
|
||||
FANCY (XFRM, xfrm, 3, 0);
|
||||
FANCY (NDEBT, ndebit, 5, 0);
|
||||
FANCY (NCRED, ncredit, 6, 0);
|
||||
|
||||
@ -441,8 +457,8 @@ configLayout (SplitRegister *reg)
|
||||
curs = reg->single_cursor;
|
||||
FANCY (DATE, date, 0, 0);
|
||||
BASIC (NUM, num, 1, 0);
|
||||
FANCY (MXFRM, mxfrm, 2, 0);
|
||||
FANCY (DESC, desc, 3, 0);
|
||||
FANCY (DESC, desc, 2, 0);
|
||||
FANCY (MXFRM, mxfrm, 3, 0);
|
||||
BASIC (RECN, recn, 4, 0);
|
||||
FANCY (DEBT, debit, 5, 0);
|
||||
FANCY (CRED, credit, 6, 0);
|
||||
@ -700,7 +716,8 @@ configTraverse (SplitRegister *reg)
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
SplitRegister * xaccMallocSplitRegister (int type)
|
||||
SplitRegister *
|
||||
xaccMallocSplitRegister (int type)
|
||||
{
|
||||
SplitRegister * reg;
|
||||
reg = (SplitRegister *) malloc (sizeof (SplitRegister));
|
||||
@ -710,39 +727,83 @@ SplitRegister * xaccMallocSplitRegister (int type)
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
void
|
||||
xaccSetSplitRegisterColors (SplitRegisterColors reg_colors_new)
|
||||
{
|
||||
reg_colors = reg_colors_new;
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
static void
|
||||
configTable(SplitRegister *reg)
|
||||
{
|
||||
int style = reg->type & REG_STYLE_MASK;
|
||||
|
||||
if ((reg == NULL) || (reg->table == NULL))
|
||||
return;
|
||||
|
||||
switch (style) {
|
||||
case REG_SINGLE_LINE:
|
||||
case REG_SINGLE_DYNAMIC:
|
||||
reg->table->alternate_bg_colors = GNC_T;
|
||||
break;
|
||||
case REG_DOUBLE_LINE:
|
||||
case REG_DOUBLE_DYNAMIC:
|
||||
reg->table->alternate_bg_colors = reg_colors.double_alternate_virt;
|
||||
break;
|
||||
default:
|
||||
reg->table->alternate_bg_colors = GNC_F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
void
|
||||
xaccSplitRegisterConfigColors (SplitRegister *reg)
|
||||
{
|
||||
reg->single_cursor->active_bg_color =
|
||||
reg_colors.single_cursor_active_bg_color;
|
||||
reg->single_cursor->passive_bg_color =
|
||||
reg_colors.single_cursor_passive_bg_color;
|
||||
reg->single_cursor->passive_bg_color2 =
|
||||
reg_colors.single_cursor_passive_bg_color2;
|
||||
|
||||
reg->double_cursor->active_bg_color =
|
||||
reg_colors.double_cursor_active_bg_color;
|
||||
reg->double_cursor->passive_bg_color =
|
||||
reg_colors.double_cursor_passive_bg_color;
|
||||
reg->double_cursor->passive_bg_color2 =
|
||||
reg_colors.double_cursor_passive_bg_color2;
|
||||
|
||||
reg->trans_cursor->active_bg_color =
|
||||
reg_colors.trans_cursor_active_bg_color;
|
||||
reg->trans_cursor->passive_bg_color =
|
||||
reg_colors.trans_cursor_passive_bg_color;
|
||||
reg->trans_cursor->passive_bg_color2 =
|
||||
reg_colors.trans_cursor_passive_bg_color;
|
||||
|
||||
reg->split_cursor->active_bg_color =
|
||||
reg_colors.split_cursor_active_bg_color;
|
||||
reg->split_cursor->passive_bg_color =
|
||||
reg_colors.split_cursor_passive_bg_color;
|
||||
reg->split_cursor->passive_bg_color2 =
|
||||
reg_colors.split_cursor_passive_bg_color;
|
||||
|
||||
reg->header->active_bg_color = reg_colors.header_bg_color;
|
||||
reg->header->passive_bg_color = reg_colors.header_bg_color;
|
||||
reg->header->passive_bg_color2 = reg_colors.header_bg_color;
|
||||
|
||||
configTable(reg);
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
|
||||
static void
|
||||
configCursors (SplitRegister *reg)
|
||||
{
|
||||
/* --------------------------- */
|
||||
/* set the color of the cells in the cursors */
|
||||
/* hack alert -- the actual color should depend on the
|
||||
* type of register. */
|
||||
/* they used to be the following, once upon a time:
|
||||
"*regbank.oddRowBackground: #aaccff",
|
||||
"*regcash.oddRowBackground: #ccffcc",
|
||||
"*regasset.oddRowBackground: #aaffcc",
|
||||
"*regcredit.oddRowBackground: #ffffaa",
|
||||
"*regliability.oddRowBackground: #ffcccc",
|
||||
"*ledportfolio.oddRowBackground: #ccffff",
|
||||
"*regmutual.oddRowBackground: #ccffff",
|
||||
"*regincome.oddRowBackground: #aaccff",
|
||||
"*regexpense.oddRowBackground: #ffcccc",
|
||||
"*regequity.oddRowBackground: #ffffaa",
|
||||
"*ledgportfolio.evenRowBackground:grey",
|
||||
"*regmutual.evenRowBackground: grey",
|
||||
*/
|
||||
reg->single_cursor->active_bg_color = 0xffdddd; /* pale red */
|
||||
reg->single_cursor->passive_bg_color = 0xccccff; /* pale blue */
|
||||
|
||||
reg->double_cursor->active_bg_color = 0xffdddd; /* pale red */
|
||||
reg->double_cursor->passive_bg_color = 0xccccff; /* pale blue */
|
||||
|
||||
reg->trans_cursor->active_bg_color = 0xffdddd; /* pale red */
|
||||
reg->trans_cursor->passive_bg_color = 0xccccff; /* pale blue */
|
||||
|
||||
reg->split_cursor->active_bg_color = 0xffffdd; /* pale yellow */
|
||||
reg->split_cursor->passive_bg_color = 0xffffff; /* white */
|
||||
|
||||
xaccSplitRegisterConfigColors(reg);
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
@ -808,6 +869,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
CellBlock *header;
|
||||
int phys_r, phys_c;
|
||||
|
||||
reg->table = NULL;
|
||||
reg->user_data = NULL;
|
||||
reg->destroy = NULL;
|
||||
reg->type = type;
|
||||
@ -854,7 +916,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
NEW (mxfrm, Combo);
|
||||
NEW (xto, Combo);
|
||||
NEW (action, Combo);
|
||||
NEW (memo, Text);
|
||||
NEW (memo, QuickFill);
|
||||
NEW (credit, Price);
|
||||
NEW (debit, Price);
|
||||
NEW (price, Price);
|
||||
@ -885,9 +947,24 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
* cells handles this for us.
|
||||
*/
|
||||
|
||||
reg -> nullCell -> input_output = XACC_CELL_ALLOW_NONE;
|
||||
reg->nullCell->input_output = XACC_CELL_ALLOW_NONE;
|
||||
xaccSetBasicCellValue (reg->nullCell, "");
|
||||
|
||||
/* The num cell is the transaction number */
|
||||
xaccSetBasicCellBlankHelp (reg->numCell, NUM_CELL_HELP);
|
||||
|
||||
/* the xfer cells */
|
||||
xaccSetBasicCellBlankHelp (®->mxfrmCell->cell, XFER_CELL_HELP);
|
||||
xaccSetBasicCellBlankHelp (®->xfrmCell->cell, XFER_CELL_HELP);
|
||||
xaccComboCellSetIgnoreString (reg->mxfrmCell, SPLIT_STR);
|
||||
xaccComboCellSetIgnoreHelp (reg->mxfrmCell, TOOLTIP_MULTI_SPLIT);
|
||||
|
||||
/* the memo cell */
|
||||
xaccSetBasicCellBlankHelp (®->memoCell->cell, MEMO_CELL_HELP);
|
||||
|
||||
/* the desc cell */
|
||||
xaccSetBasicCellBlankHelp (®->descCell->cell, DESC_CELL_HELP);
|
||||
|
||||
/* balance cell does not accept input; its display only. */
|
||||
/* however, we *do* want it to shadow the true cell contents when
|
||||
* the cursor is repositioned. Othewise, it will just display
|
||||
@ -901,17 +978,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
*/
|
||||
reg->recnCell->input_output |= XACC_CELL_ALLOW_EXACT_ONLY;
|
||||
|
||||
/* the debit/credit/value cells show blank if value is 0.00 */
|
||||
reg->debitCell->blank_zero = 1;
|
||||
reg->creditCell->blank_zero = 1;
|
||||
reg->valueCell->blank_zero = 1;
|
||||
reg->ndebitCell->blank_zero = 1;
|
||||
reg->ncreditCell->blank_zero = 1;
|
||||
|
||||
/* ok, now make sure the initail value of 0.0 is blanked.
|
||||
* if this is not done, then various oddball situations
|
||||
* will show the non-blanked values.
|
||||
*/
|
||||
/* Initialize price cells */
|
||||
xaccSetPriceCellValue (reg->debitCell, 0.0);
|
||||
xaccSetPriceCellValue (reg->creditCell, 0.0);
|
||||
xaccSetPriceCellValue (reg->valueCell, 0.0);
|
||||
@ -920,27 +987,31 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
|
||||
/* The format for share-related info is a printf-style
|
||||
* format string for a double. */
|
||||
xaccSetPriceCellFormat (reg->shrsCell, SHRS_CELL_FORMAT);
|
||||
xaccSetPriceCellMonetary (reg->shrsCell, GNC_F);
|
||||
xaccSetPriceCellMinTrailZeros (reg->shrsCell, 0);
|
||||
xaccSetPriceCellPrecision (reg->shrsCell, SHARES_PRECISION);
|
||||
|
||||
/* The action cell should accept strings not in the list */
|
||||
xaccComboCellSetStrict (reg->actionCell, GNC_F);
|
||||
xaccSetBasicCellBlankHelp (®->actionCell->cell, ACTION_CELL_HELP);
|
||||
|
||||
/* number format for share quantities in stock ledgers */
|
||||
switch (type & REG_TYPE_MASK) {
|
||||
case STOCK_REGISTER:
|
||||
case PORTFOLIO:
|
||||
case CURRENCY_REGISTER:
|
||||
xaccSetPriceCellFormat (reg->debitCell, DEBIT_CELL_FORMAT);
|
||||
xaccSetPriceCellFormat (reg->creditCell, CREDIT_CELL_FORMAT);
|
||||
xaccSetPriceCellFormat (reg->ndebitCell, DEBIT_CELL_FORMAT);
|
||||
xaccSetPriceCellFormat (reg->ncreditCell, CREDIT_CELL_FORMAT);
|
||||
xaccSetPriceCellFormat (reg->priceCell, DEBIT_CELL_FORMAT);
|
||||
xaccSetPriceCellMonetary (reg->debitCell, GNC_F);
|
||||
xaccSetPriceCellMonetary (reg->creditCell, GNC_F);
|
||||
xaccSetPriceCellMonetary (reg->ndebitCell, GNC_F);
|
||||
xaccSetPriceCellMonetary (reg->ncreditCell, GNC_F);
|
||||
xaccSetPriceCellMonetary (reg->priceCell, GNC_F);
|
||||
xaccSetPriceCellMinTrailZeros (reg->debitCell, 0);
|
||||
xaccSetPriceCellMinTrailZeros (reg->creditCell, 0);
|
||||
xaccSetPriceCellMinTrailZeros (reg->ndebitCell, 0);
|
||||
xaccSetPriceCellMinTrailZeros (reg->ncreditCell, 0);
|
||||
|
||||
xaccSetPriceCellPrecision (reg->debitCell, SHARES_PRECISION);
|
||||
xaccSetPriceCellPrecision (reg->creditCell, SHARES_PRECISION);
|
||||
xaccSetPriceCellPrecision (reg->ndebitCell, SHARES_PRECISION);
|
||||
xaccSetPriceCellPrecision (reg->ncreditCell, SHARES_PRECISION);
|
||||
xaccSetPriceCellPrecision (reg->priceCell, SHARES_PRECISION);
|
||||
|
||||
xaccSetBasicCellBlankHelp (®->priceCell->cell, PRICE_CELL_HELP);
|
||||
xaccSetBasicCellBlankHelp (®->valueCell->cell, VALUE_CELL_HELP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -958,6 +1029,7 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
|
||||
/* -------------------------------- */
|
||||
phys_r = header->numRows;
|
||||
reg->cursor_phys_col = 0;
|
||||
reg->cursor_phys_row = phys_r; /* cursor on first line past header */
|
||||
reg->cursor_virt_row = 1;
|
||||
|
||||
@ -986,6 +1058,8 @@ xaccInitSplitRegister (SplitRegister *reg, int type)
|
||||
xaccMoveCursor (table, header->numRows, 0);
|
||||
|
||||
reg->table = table;
|
||||
|
||||
configTable(reg);
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
@ -997,12 +1071,14 @@ xaccConfigSplitRegister (SplitRegister *reg, int newtype)
|
||||
|
||||
reg->type = newtype;
|
||||
|
||||
/* Make sure that any GU elemnts associated with this reconfig
|
||||
/* Make sure that any GUI elements associated with this reconfig
|
||||
* are properly initialized. */
|
||||
xaccCreateCursor (reg->table, reg->single_cursor);
|
||||
xaccCreateCursor (reg->table, reg->double_cursor);
|
||||
xaccCreateCursor (reg->table, reg->trans_cursor);
|
||||
xaccCreateCursor (reg->table, reg->split_cursor);
|
||||
|
||||
configTable(reg);
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
@ -1042,7 +1118,7 @@ xaccDestroySplitRegister (SplitRegister *reg)
|
||||
xaccDestroyComboCell (reg->xfrmCell);
|
||||
xaccDestroyComboCell (reg->mxfrmCell);
|
||||
xaccDestroyComboCell (reg->xtoCell);
|
||||
xaccDestroyBasicCell (reg->memoCell);
|
||||
xaccDestroyQuickFillCell (reg->memoCell);
|
||||
xaccDestroyPriceCell (reg->creditCell);
|
||||
xaccDestroyPriceCell (reg->debitCell);
|
||||
xaccDestroyPriceCell (reg->priceCell);
|
||||
@ -1093,7 +1169,7 @@ xaccSplitRegisterGetChangeFlag (SplitRegister *reg)
|
||||
changed |= MOD_XFRM & reg->xfrmCell->cell.changed;
|
||||
changed |= MOD_MXFRM & reg->mxfrmCell->cell.changed;
|
||||
changed |= MOD_XTO & reg->xtoCell->cell.changed;
|
||||
changed |= MOD_MEMO & reg->memoCell->changed;
|
||||
changed |= MOD_MEMO & reg->memoCell->cell.changed;
|
||||
changed |= MOD_AMNT & reg->creditCell->cell.changed;
|
||||
changed |= MOD_AMNT & reg->debitCell->cell.changed;
|
||||
changed |= MOD_PRIC & reg->priceCell->cell.changed;
|
||||
@ -1119,7 +1195,7 @@ xaccSplitRegisterClearChangeFlag (SplitRegister *reg)
|
||||
reg->xfrmCell->cell.changed = 0;
|
||||
reg->mxfrmCell->cell.changed = 0;
|
||||
reg->xtoCell->cell.changed = 0;
|
||||
reg->memoCell->changed = 0;
|
||||
reg->memoCell->cell.changed = 0;
|
||||
reg->creditCell->cell.changed = 0;
|
||||
reg->debitCell->cell.changed = 0;
|
||||
reg->priceCell->cell.changed = 0;
|
||||
|
@ -143,7 +143,7 @@ struct _SplitRegister {
|
||||
ComboCell * xfrmCell;
|
||||
ComboCell * mxfrmCell;
|
||||
ComboCell * xtoCell;
|
||||
BasicCell * memoCell;
|
||||
QuickFillCell * memoCell;
|
||||
PriceCell * creditCell;
|
||||
PriceCell * debitCell;
|
||||
PriceCell * priceCell;
|
||||
@ -177,14 +177,41 @@ struct _SplitRegister {
|
||||
/* The destroy callback gives user's a chance
|
||||
* to free up any associated user_hook data */
|
||||
void (* destroy) (SplitRegister *);
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef struct _SplitRegisterColors SplitRegisterColors;
|
||||
|
||||
struct _SplitRegisterColors
|
||||
{
|
||||
uint32 single_cursor_active_bg_color;
|
||||
uint32 single_cursor_passive_bg_color;
|
||||
uint32 single_cursor_passive_bg_color2;
|
||||
|
||||
uint32 double_cursor_active_bg_color;
|
||||
uint32 double_cursor_passive_bg_color;
|
||||
uint32 double_cursor_passive_bg_color2;
|
||||
|
||||
gncBoolean double_alternate_virt;
|
||||
|
||||
uint32 trans_cursor_active_bg_color;
|
||||
uint32 trans_cursor_passive_bg_color;
|
||||
|
||||
uint32 split_cursor_active_bg_color;
|
||||
uint32 split_cursor_passive_bg_color;
|
||||
|
||||
uint32 header_bg_color;
|
||||
};
|
||||
|
||||
|
||||
SplitRegister * xaccMallocSplitRegister (int type);
|
||||
void xaccInitSplitRegister (SplitRegister *, int type);
|
||||
void xaccConfigSplitRegister (SplitRegister *, int type);
|
||||
void xaccDestroySplitRegister (SplitRegister *);
|
||||
|
||||
void xaccSetSplitRegisterColors (SplitRegisterColors reg_colors);
|
||||
void xaccSplitRegisterConfigColors (SplitRegister *reg);
|
||||
|
||||
/* returns non-zero value if updates have been made to data */
|
||||
unsigned int xaccSplitRegisterGetChangeFlag (SplitRegister *);
|
||||
|
||||
|
@ -75,6 +75,7 @@ xaccInitTable (Table * table)
|
||||
|
||||
table->move_cursor = NULL;
|
||||
table->traverse = NULL;
|
||||
table->set_help = NULL;
|
||||
table->client_data = NULL;
|
||||
|
||||
table->entries = NULL;
|
||||
@ -85,6 +86,8 @@ xaccInitTable (Table * table)
|
||||
table->user_data = NULL;
|
||||
table->handlers = NULL;
|
||||
|
||||
table->alternate_bg_colors = GNC_F;
|
||||
|
||||
/* invalidate the "previous" traversed cell */
|
||||
table->prev_phys_traverse_row = -1;
|
||||
table->prev_phys_traverse_col = -1;
|
||||
@ -376,7 +379,7 @@ makePassive (Table *table)
|
||||
int phys_row = table->current_cursor_phys_row;
|
||||
int phys_col = table->current_cursor_phys_col;
|
||||
int r_origin, c_origin;
|
||||
|
||||
int virt_row;
|
||||
|
||||
/* Change the cell background colors to their "passive" values.
|
||||
* This denotes that the cursor has left this location (which means more or
|
||||
@ -390,21 +393,27 @@ makePassive (Table *table)
|
||||
r_origin -= table->locators[phys_row][phys_col]->phys_row_offset;
|
||||
c_origin -= table->locators[phys_row][phys_col]->phys_col_offset;
|
||||
|
||||
virt_row = table->locators[phys_row][phys_col]->virt_row;
|
||||
|
||||
curs = table->current_cursor;
|
||||
|
||||
for (i=0; i<curs->numRows; i++) {
|
||||
for (j=0; j<curs->numCols; j++) {
|
||||
BasicCell *cell;
|
||||
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.
|
||||
* first line is whatever was speced, the second line is white.
|
||||
*/
|
||||
if (0==i) {
|
||||
table->bg_colors[i+r_origin][j+c_origin] = curs->passive_bg_color;
|
||||
} else {
|
||||
table->bg_colors[i+r_origin][j+c_origin] = 0xffffff;
|
||||
}
|
||||
if (table->alternate_bg_colors) {
|
||||
if ((virt_row % 2) == 1)
|
||||
color = curs->passive_bg_color;
|
||||
else
|
||||
color = curs->passive_bg_color2;
|
||||
}
|
||||
else if (0 == i)
|
||||
color = curs->passive_bg_color;
|
||||
else
|
||||
color = curs->passive_bg_color2;
|
||||
|
||||
table->bg_colors[i+r_origin][j+c_origin] = color;
|
||||
|
||||
cell = curs->cells[i][j];
|
||||
if (cell) {
|
||||
@ -935,14 +944,29 @@ gnc_table_enter_update(Table *table, int row, int col, int *cursor_position,
|
||||
* different, freeing the old one. (Doing a strcmp would leak memory).
|
||||
*/
|
||||
if (retval && (val != retval)) {
|
||||
if (safe_strcmp(retval, val) != 0)
|
||||
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
|
||||
if (table->entries[row][col]) free (table->entries[row][col]);
|
||||
table->entries[row][col] = retval;
|
||||
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
|
||||
} else {
|
||||
retval = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->set_help)
|
||||
{
|
||||
BasicCell *cell;
|
||||
char *help_str;
|
||||
|
||||
cell = arr->cells[rel_row][rel_col];
|
||||
help_str = xaccBasicCellGetHelp(cell);
|
||||
|
||||
table->set_help(table, help_str, table->client_data);
|
||||
|
||||
if (help_str != NULL)
|
||||
free(help_str);
|
||||
}
|
||||
|
||||
/* record this position as the cell that will be
|
||||
* traversed out of if a traverse even happens */
|
||||
table->prev_phys_traverse_row = row;
|
||||
@ -1017,7 +1041,8 @@ gnc_table_leave_update(Table *table, int row, int col,
|
||||
/* ==================================================== */
|
||||
|
||||
const char *
|
||||
gnc_table_modify_update(Table *table, int row, int col,
|
||||
gnc_table_modify_update(Table *table,
|
||||
int row, int col,
|
||||
const char *oldval,
|
||||
const char *change,
|
||||
char *newval,
|
||||
@ -1037,7 +1062,9 @@ gnc_table_modify_update(Table *table, int row, int col,
|
||||
const char * (*mv) (BasicCell *,
|
||||
const char *, const char *, const char *,
|
||||
int *, int *, int *);
|
||||
|
||||
const char *retval = NULL;
|
||||
|
||||
ENTER ("gnc_table_modify_update()\n");
|
||||
|
||||
/* OK, if there is a callback for this cell, call it */
|
||||
@ -1061,6 +1088,21 @@ gnc_table_modify_update(Table *table, int row, int col,
|
||||
retval = newval;
|
||||
(arr->cells[rel_row][rel_col])->changed = 0xffffffff;
|
||||
}
|
||||
|
||||
if (table->set_help)
|
||||
{
|
||||
BasicCell *cell;
|
||||
char *help_str;
|
||||
|
||||
cell = arr->cells[rel_row][rel_col];
|
||||
help_str = xaccBasicCellGetHelp(cell);
|
||||
|
||||
table->set_help(table, help_str, table->client_data);
|
||||
|
||||
if (help_str != NULL)
|
||||
free(help_str);
|
||||
}
|
||||
|
||||
LEAVE ("gnc_table_modify_update(): "
|
||||
"change %d %d (relrow=%d relcol=%d) cell=%p val=%s\n",
|
||||
row, col, rel_row, rel_col,
|
||||
@ -1071,6 +1113,54 @@ gnc_table_modify_update(Table *table, int row, int col,
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
gncBoolean
|
||||
gnc_table_direct_update(Table *table,
|
||||
int row, int col,
|
||||
const char *oldval,
|
||||
char **newval_ptr,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection,
|
||||
void *gui_data)
|
||||
{
|
||||
CellBlock *arr = table->current_cursor;
|
||||
|
||||
const int rel_row = table->locators[row][col]->phys_row_offset;
|
||||
const int rel_col = table->locators[row][col]->phys_col_offset;
|
||||
|
||||
BasicCell *cell = arr->cells[rel_row][rel_col];
|
||||
|
||||
gncBoolean result;
|
||||
|
||||
if (cell->direct_update == NULL)
|
||||
return GNC_F;
|
||||
|
||||
result = cell->direct_update(cell, oldval, newval_ptr, cursor_position,
|
||||
start_selection, end_selection, gui_data);
|
||||
|
||||
if ((*newval_ptr != oldval) && (*newval_ptr != NULL)) {
|
||||
if (table->entries[row][col]) free (table->entries[row][col]);
|
||||
table->entries[row][col] = *newval_ptr;
|
||||
cell->changed = 0xffffffff;
|
||||
}
|
||||
|
||||
if (table->set_help)
|
||||
{
|
||||
char *help_str;
|
||||
|
||||
help_str = xaccBasicCellGetHelp(cell);
|
||||
|
||||
table->set_help(table, help_str, table->client_data);
|
||||
|
||||
if (help_str != NULL)
|
||||
free(help_str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
gncBoolean
|
||||
gnc_table_find_valid_cell_horiz(Table *table, int *row, int *col,
|
||||
gncBoolean exact_cell)
|
||||
|
@ -154,6 +154,10 @@ struct _RevLocator {
|
||||
|
||||
typedef struct _RevLocator RevLocator;
|
||||
|
||||
typedef void (*TableSetHelpFunc) (Table *table,
|
||||
const char *help_str,
|
||||
void *client_data);
|
||||
|
||||
|
||||
/* The number of "physical" rows/cols is the number
|
||||
* of displayed one-line gui rows/cols in the table.
|
||||
@ -202,6 +206,8 @@ struct _Table {
|
||||
int *p_new_phys_col,
|
||||
void *client_data);
|
||||
|
||||
TableSetHelpFunc set_help;
|
||||
|
||||
void * client_data;
|
||||
|
||||
/* string values for each cell,
|
||||
@ -214,6 +220,12 @@ struct _Table {
|
||||
uint32 **bg_colors;
|
||||
uint32 **fg_colors;
|
||||
|
||||
/* Determines whether the passive background
|
||||
* colors alternate between odd and even virt
|
||||
* rows, or between the first and non-first
|
||||
* physical rows within cellblocks. */
|
||||
gncBoolean alternate_bg_colors;
|
||||
|
||||
/* handler locators for each cell,
|
||||
* of dimension num_phys_rows * num_phys_cols */
|
||||
Locator ***locators;
|
||||
@ -363,17 +375,20 @@ xaccRefreshCursorGUI (Table * table, gncBoolean do_scroll);
|
||||
* However, don't just change it, because it will break functional code.
|
||||
*/
|
||||
const char *
|
||||
gnc_table_enter_update(Table *table, int row, int col,
|
||||
gnc_table_enter_update(Table *table,
|
||||
int row, int col,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection);
|
||||
|
||||
const char *
|
||||
gnc_table_leave_update(Table *table, int row, int col,
|
||||
gnc_table_leave_update(Table *table,
|
||||
int row, int col,
|
||||
const char* old_text);
|
||||
|
||||
const char *
|
||||
gnc_table_modify_update(Table *table, int row, int col,
|
||||
gnc_table_modify_update(Table *table,
|
||||
int row, int col,
|
||||
const char *oldval,
|
||||
const char *change,
|
||||
char *newval,
|
||||
@ -382,7 +397,18 @@ gnc_table_modify_update(Table *table, int row, int col,
|
||||
int *end_selection);
|
||||
|
||||
gncBoolean
|
||||
gnc_table_traverse_update(Table *table, int row, int col,
|
||||
gnc_table_direct_update(Table *table,
|
||||
int row, int col,
|
||||
const char *oldval,
|
||||
char **newval_ptr,
|
||||
int *cursor_position,
|
||||
int *start_selection,
|
||||
int *end_selection,
|
||||
void *gui_data);
|
||||
|
||||
gncBoolean
|
||||
gnc_table_traverse_update(Table *table,
|
||||
int row, int col,
|
||||
gncTableTraversalDir dir,
|
||||
int *dest_row,
|
||||
int *dest_col);
|
||||
|
@ -107,8 +107,6 @@ xaccCreateTable (GtkWidget *widget, void *data)
|
||||
gnucash_sheet_table_load (sheet);
|
||||
gnucash_sheet_cursor_set_from_table (sheet, TRUE);
|
||||
gnucash_sheet_redraw_all (sheet);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -116,6 +114,8 @@ void
|
||||
xaccRefreshTableGUI (Table * table)
|
||||
{
|
||||
GnucashSheet *sheet;
|
||||
SheetBlockStyle *style;
|
||||
SplitRegister *sr;
|
||||
|
||||
if (!table)
|
||||
return;
|
||||
@ -125,6 +125,27 @@ xaccRefreshTableGUI (Table * table)
|
||||
g_return_if_fail (GNUCASH_IS_SHEET (table->table_widget));
|
||||
|
||||
sheet = GNUCASH_SHEET(table->table_widget);
|
||||
sr = (SplitRegister *)sheet->split_register;
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_HEADER];
|
||||
gnucash_sheet_style_recompile (style, sr->header, sr,
|
||||
GNUCASH_CURSOR_HEADER);
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_SINGLE];
|
||||
gnucash_sheet_style_recompile (style, sr->single_cursor,
|
||||
sr, GNUCASH_CURSOR_SINGLE);
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_DOUBLE];
|
||||
gnucash_sheet_style_recompile (style, sr->double_cursor,
|
||||
sr, GNUCASH_CURSOR_DOUBLE);
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_TRANS];
|
||||
gnucash_sheet_style_recompile (style, sr->trans_cursor,
|
||||
sr, GNUCASH_CURSOR_TRANS);
|
||||
|
||||
style = sheet->cursor_style[GNUCASH_CURSOR_SPLIT];
|
||||
gnucash_sheet_style_recompile (style, sr->split_cursor,
|
||||
sr, GNUCASH_CURSOR_SPLIT);
|
||||
|
||||
gnucash_sheet_table_load (sheet);
|
||||
|
||||
|
@ -7,6 +7,20 @@
|
||||
|
||||
;; (use-modules (gnc))
|
||||
|
||||
(define (display-slib-error)
|
||||
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
|
||||
(newline)
|
||||
(display "If you have slib installed, you may need to create\n")
|
||||
(display "a symbolic link named 'slib' from the guile directory\n")
|
||||
(display "(usually /usr/share/guile) to the directory where slib\n")
|
||||
(display "is installed.\n\n")
|
||||
(display "You may also need to run the following command as root:")
|
||||
(newline)
|
||||
(newline)
|
||||
(display " guile -c \"(use-modules (ice-9 slib)) (require 'new-catalog)\"")
|
||||
(newline)
|
||||
(newline))
|
||||
|
||||
;; Test for slib.
|
||||
(let* ((try-slib (lambda () (use-modules (ice-9 slib))))
|
||||
(handler (lambda args #f))
|
||||
@ -14,27 +28,22 @@
|
||||
(if (not result)
|
||||
(begin
|
||||
(newline)
|
||||
(display "It appears you do not have the 'slib' scheme\n")
|
||||
(display "library installed. You need slib2c6 or later\n")
|
||||
(display "It appears you do not have the 'slib' scheme ")
|
||||
(display "library installed.\nYou need slib2c4 or later ")
|
||||
(display "to run GnuCash.\n")
|
||||
(newline)
|
||||
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
|
||||
(newline)
|
||||
(display-slib-error)
|
||||
(exit 1))))
|
||||
|
||||
;; This variable determines whether slib-backup.scm gets loaded.
|
||||
(define gnc:*load-slib-backup* #f)
|
||||
|
||||
;; Test for slib >= 2c6.
|
||||
(let* ((try-slib (lambda () (require 'printf) (sprintf #f "test")))
|
||||
(handler (lambda args #f))
|
||||
(result (catch #t try-slib handler)))
|
||||
(if (not result)
|
||||
(begin
|
||||
(newline)
|
||||
(display "It appears your 'slib' scheme library is out\n")
|
||||
(display "of date. You need slib2c6 or later to run GnuCash.\n")
|
||||
(newline)
|
||||
(display "Obtain slib at: http://swissnet.ai.mit.edu/~jaffer/SLIB.html\n")
|
||||
(newline)
|
||||
(exit 1))))
|
||||
(set! gnc:*load-slib-backup* #t)))
|
||||
|
||||
|
||||
(define (build-path firstelement . restofpath)
|
||||
|
@ -1,4 +1,3 @@
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'hash-table)
|
||||
|
||||
(define gnc:register-c-side-scheme-ptr #f)
|
||||
@ -22,3 +21,23 @@
|
||||
|
||||
(set! gnc:register-c-side-scheme-ptr register-c-side-scheme-ptr)
|
||||
(set! gnc:unregister-c-side-scheme-ptr-id unregister-c-side-scheme-ptr-id))
|
||||
|
||||
|
||||
(define (gnc:error->string tag args)
|
||||
(define (write-error port)
|
||||
(if (and (list? args) (not (null? args)))
|
||||
(let ((func (car args)))
|
||||
(if func
|
||||
(begin
|
||||
(display "Function: " port)
|
||||
(display func port)
|
||||
(display ", " port)
|
||||
(display tag port)
|
||||
(display "\n\n" port)))))
|
||||
(false-if-exception
|
||||
(apply display-error #f port args))
|
||||
;; Here we should write the stack trace.
|
||||
)
|
||||
|
||||
(false-if-exception
|
||||
(call-with-output-string write-error)))
|
||||
|
@ -1,19 +1,105 @@
|
||||
|
||||
(gnc:support "extensions.scm")
|
||||
|
||||
|
||||
(define (gnc:make-extension
|
||||
;; The type of extension item, either 'menu, 'menu-item, or 'separator
|
||||
type
|
||||
;; The name of the extension in the menu
|
||||
name
|
||||
;; The tooltip
|
||||
documentation-string
|
||||
;; A list of names indicating the menus under which this item is
|
||||
;; located. The last item indicates the item *after* which this
|
||||
;; extension will go.
|
||||
path
|
||||
;; The script to call when the menu item is selected
|
||||
script)
|
||||
(vector type
|
||||
name
|
||||
documentation-string
|
||||
path
|
||||
script))
|
||||
|
||||
(define (gnc:extension-type extension)
|
||||
(vector-ref extension 0))
|
||||
(define (gnc:extension-name extension)
|
||||
(vector-ref extension 1))
|
||||
(define (gnc:extension-documentation extension)
|
||||
(vector-ref extension 2))
|
||||
(define (gnc:extension-path extension)
|
||||
(vector-ref extension 3))
|
||||
(define (gnc:extension-script extension)
|
||||
(vector-ref extension 4))
|
||||
|
||||
(define (gnc:make-menu-item name documentation-string path script)
|
||||
(gnc:make-extension 'menu-item name documentation-string path script))
|
||||
|
||||
(define (gnc:make-menu name path)
|
||||
(gnc:make-extension 'menu name #f path #f))
|
||||
|
||||
(define (gnc:make-separator path)
|
||||
(gnc:make-extension 'separator #f #f path #f))
|
||||
|
||||
|
||||
(define (gnc:extensions-menu-setup win)
|
||||
;; Should take window as a parameter?
|
||||
|
||||
(gnc:debug "Setting up extensions menu " win "\n")
|
||||
(define menu (gnc:make-menu "Extensions" (list "_Settings")))
|
||||
|
||||
(gnc:extensions-menu-add-item "Export data as text (Danger: Unfinished)"
|
||||
(define export-item
|
||||
(gnc:make-menu-item "Export data as text (Danger: Unfinished)"
|
||||
"Export data as text."
|
||||
(lambda ()
|
||||
(gnc:main-win-export-data-as-text win)))
|
||||
(list "Extensions" "")
|
||||
(lambda () (gnc:main-win-export-data-as-text win))))
|
||||
|
||||
(gnc:extensions-menu-add-item "QIF File Import (Danger: Unfinished)"
|
||||
(define qif-item
|
||||
(gnc:make-menu-item "QIF File Import (Danger: Unfinished)"
|
||||
"Import QIF File - Scripted in Guile."
|
||||
(lambda ()
|
||||
(gnc:extensions-qif-import win))))
|
||||
(list "Extensions"
|
||||
"Export data as text (Danger: Unfinished)")
|
||||
(lambda () (gnc:extensions-qif-import win))))
|
||||
|
||||
(gnc:hook-add-dangler gnc:*main-window-opened-hook* gnc:extensions-menu-setup)
|
||||
(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)
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
(define (gnc:startup)
|
||||
(gnc:debug "starting up.")
|
||||
(if (not (gnc:handle-command-line-args))
|
||||
@ -14,10 +13,9 @@
|
||||
;; Now we can load a bunch of files.
|
||||
|
||||
(gnc:depend "doc.scm")
|
||||
(gnc:depend "extensions.scm") ; Should this be here or somewhere else?
|
||||
(gnc:depend "extensions.scm")
|
||||
(gnc:depend "text-export.scm")
|
||||
(gnc:depend "importqif.scm")
|
||||
(gnc:depend "test.scm")
|
||||
(gnc:depend "report.scm")
|
||||
|
||||
;; FIXME: These do not belong here, but for now, we're putting them
|
||||
@ -28,10 +26,18 @@
|
||||
;;
|
||||
;; Just load these since we might want to redefine them on the fly
|
||||
;; and we're going to change this mechanism anyway...
|
||||
(gnc:load "report/hello-world.scm")
|
||||
(gnc:load "report/balance-and-pnl.scm")
|
||||
(gnc:load "report/transaction-report.scm")
|
||||
(gnc:load "report/average-balance.scm")
|
||||
(let
|
||||
((repdir
|
||||
(opendir (string-append gnc:_share-dir-default_ "/scm/report"))))
|
||||
(while (let ((cf (readdir repdir)))
|
||||
(if (string? cf)
|
||||
(if (and
|
||||
(not (directory? cf))
|
||||
(> (string-length cf) 4))
|
||||
(if (string=? (substring cf (- (string-length cf) 4)
|
||||
(string-length cf)) ".scm")
|
||||
(gnc:load (string-append "report/" cf)))))
|
||||
(string? cf)) ()))
|
||||
|
||||
;; Load the system configs
|
||||
(if (not (gnc:load-system-config-if-needed))
|
||||
@ -67,8 +73,8 @@
|
||||
(gnc:ui-shutdown))))
|
||||
|
||||
(else
|
||||
(gnc:hook-run-danglers gnc:*shutdown-hook*)
|
||||
(gnc:ui-destroy)
|
||||
(gnc:hook-run-danglers gnc:*shutdown-hook*)
|
||||
(exit exit-status))))
|
||||
|
||||
(define (gnc:ui-finish)
|
||||
|
@ -69,6 +69,10 @@
|
||||
(let ((getter (gnc:option-getter option)))
|
||||
(getter)))
|
||||
|
||||
(define (gnc:option-default-value option)
|
||||
(let ((getter (gnc:option-default-getter option)))
|
||||
(getter)))
|
||||
|
||||
(define (gnc:restore-form-generator value->string)
|
||||
(lambda () (string-append
|
||||
"(lambda (option) "
|
||||
@ -76,6 +80,10 @@
|
||||
(value->string)
|
||||
")))")))
|
||||
|
||||
(define (gnc:value->string value)
|
||||
(call-with-output-string
|
||||
(lambda (port) (write value port))))
|
||||
|
||||
(define (gnc:make-string-option
|
||||
section
|
||||
name
|
||||
@ -83,7 +91,7 @@
|
||||
documentation-string
|
||||
default-value)
|
||||
(let* ((value default-value)
|
||||
(value->string (lambda () (string-append "\"" value "\""))))
|
||||
(value->string (lambda () (gnc:value->string value))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'string documentation-string
|
||||
(lambda () value)
|
||||
@ -102,7 +110,7 @@
|
||||
documentation-string
|
||||
default-value)
|
||||
(let* ((value default-value)
|
||||
(value->string (lambda () (if value "#t" "#f"))))
|
||||
(value->string (lambda () (gnc:value->string value))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'boolean documentation-string
|
||||
(lambda () value)
|
||||
@ -129,10 +137,8 @@
|
||||
(and (pair? date) (exact? (car date)) (exact? (cdr date))))
|
||||
|
||||
(let* ((value (default-getter))
|
||||
(value->string
|
||||
(lambda ()
|
||||
(string-append "(" (number->string (car value))
|
||||
" . " (number->string (cdr value)) ")"))))
|
||||
(value->string (lambda ()
|
||||
(string-append "'" (gnc:value->string value)))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'date documentation-string
|
||||
(lambda () value)
|
||||
@ -200,7 +206,7 @@
|
||||
|
||||
(let* ((value default-value)
|
||||
(value->string (lambda ()
|
||||
(string-append "'" (symbol->string value)))))
|
||||
(string-append "'" (gnc:value->string value)))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'multichoice documentation-string
|
||||
(lambda () value)
|
||||
@ -216,6 +222,100 @@
|
||||
(list #f "multichoice-option: illegal choice")))
|
||||
ok-values)))
|
||||
|
||||
;; number range options use the option-data as a list whose
|
||||
;; elements are: (lower-bound upper-bound num-decimals step-size)
|
||||
(define (gnc:make-number-range-option
|
||||
section
|
||||
name
|
||||
sort-tag
|
||||
documentation-string
|
||||
default-value
|
||||
lower-bound
|
||||
upper-bound
|
||||
num-decimals
|
||||
step-size)
|
||||
(let* ((value default-value)
|
||||
(value->string (lambda () (number->string value))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'number-range documentation-string
|
||||
(lambda () value)
|
||||
(lambda (x) (set! value x))
|
||||
(lambda () default-value)
|
||||
(gnc:restore-form-generator value->string)
|
||||
(lambda (x)
|
||||
(cond ((not (number? x)) (list #f "number-range-option: not a number"))
|
||||
((and (>= value lower-bound)
|
||||
(<= value upper-bound))
|
||||
(list #t x))
|
||||
(else (list #f "number-range-option: out of range"))))
|
||||
(list lower-bound upper-bound num-decimals step-size))))
|
||||
|
||||
;; Color options store rgba values in a list.
|
||||
;; The option-data is a list, whose first element
|
||||
;; is the range of possible rgba values and whose
|
||||
;; second element is a boolean indicating whether
|
||||
;; to use alpha transparency.
|
||||
(define (gnc:make-color-option
|
||||
section
|
||||
name
|
||||
sort-tag
|
||||
documentation-string
|
||||
default-value
|
||||
range
|
||||
use-alpha)
|
||||
|
||||
(define (canonicalize values)
|
||||
(map exact->inexact values))
|
||||
|
||||
(define (values-in-range values)
|
||||
(if (null? values)
|
||||
#t
|
||||
(let ((value (car values)))
|
||||
(and (number? value)
|
||||
(>= value 0)
|
||||
(<= value range)
|
||||
(values-in-range (cdr values))))))
|
||||
|
||||
(define (validate-color color)
|
||||
(cond ((not (list? color)) (list #f "color-option: not a list"))
|
||||
((not (= 4 (length color))) (list #f "color-option: wrong length"))
|
||||
((not (values-in-range color))
|
||||
(list #f "color-option: bad color values"))
|
||||
(else (list #t color))))
|
||||
|
||||
(let* ((value (canonicalize default-value))
|
||||
(value->string (lambda ()
|
||||
(string-append "'" (gnc:value->string value)))))
|
||||
(gnc:make-option
|
||||
section name sort-tag 'color documentation-string
|
||||
(lambda () value)
|
||||
(lambda (x) (set! value (canonicalize x)))
|
||||
(lambda () (canonicalize default-value))
|
||||
(gnc:restore-form-generator value->string)
|
||||
validate-color
|
||||
(list range use-alpha))))
|
||||
|
||||
(define (gnc:color->html color range)
|
||||
|
||||
(define (html-value value)
|
||||
(inexact->exact
|
||||
(min 255.0
|
||||
(truncate (* (/ 255.0 range) value)))))
|
||||
|
||||
(let ((red (car color))
|
||||
(green (cadr color))
|
||||
(blue (caddr color)))
|
||||
(string-append
|
||||
"#"
|
||||
(number->string (html-value red) 16)
|
||||
(number->string (html-value green) 16)
|
||||
(number->string (html-value blue) 16))))
|
||||
|
||||
(define (gnc:color-option->html color-option)
|
||||
(let ((color (gnc:option-value color-option))
|
||||
(range (car (gnc:option-data color-option))))
|
||||
(gnc:color->html color range)))
|
||||
|
||||
|
||||
;; Create a new options database
|
||||
(define (gnc:new-options)
|
||||
@ -279,7 +379,8 @@
|
||||
section-hash))
|
||||
(hash-for-each
|
||||
(lambda (section hash)
|
||||
(section-thunk section hash)
|
||||
(if section-thunk
|
||||
(section-thunk section hash))
|
||||
(if option-thunk
|
||||
(section-for-each hash option-thunk)))
|
||||
option-hash))
|
||||
@ -302,16 +403,18 @@
|
||||
(string-append "\n; Section: " section "\n\n")
|
||||
port))
|
||||
(lambda (option)
|
||||
(let ((value (gnc:option-value option))
|
||||
(default-value (gnc:option-default-value option)))
|
||||
(if
|
||||
(not (equal? value default-value))
|
||||
(let* ((generator (gnc:option-generate-restore-form option))
|
||||
(restore-code (false-if-exception (generator))))
|
||||
(if restore-code
|
||||
(display
|
||||
(generate-option-restore-form option restore-code)
|
||||
port))))))
|
||||
port))))))))
|
||||
|
||||
(let ((header "; GnuCash Configuration Options\n\n")
|
||||
(forms (call-with-output-string generate-forms)))
|
||||
(string-append header forms)))
|
||||
(call-with-output-string generate-forms))
|
||||
|
||||
(define (register-callback section name callback)
|
||||
(let ((id last-callback-id)
|
||||
@ -344,15 +447,16 @@
|
||||
(clear-changes))
|
||||
|
||||
(define (dispatch key)
|
||||
(cond ((eq? key 'lookup) lookup-option)
|
||||
((eq? key 'register-option) register-option)
|
||||
((eq? key 'register-callback) register-callback)
|
||||
((eq? key 'unregister-callback-id) unregister-callback-id)
|
||||
((eq? key 'for-each) options-for-each)
|
||||
((eq? key 'for-each-general) options-for-each-general)
|
||||
((eq? key 'generate-restore-forms) generate-restore-forms)
|
||||
((eq? key 'clear-changes) clear-changes)
|
||||
((eq? key 'run-callbacks) run-callbacks)
|
||||
(case key
|
||||
((lookup) lookup-option)
|
||||
((register-option) register-option)
|
||||
((register-callback) register-callback)
|
||||
((unregister-callback-id) unregister-callback-id)
|
||||
((for-each) options-for-each)
|
||||
((for-each-general) options-for-each-general)
|
||||
((generate-restore-forms) generate-restore-forms)
|
||||
((clear-changes) clear-changes)
|
||||
((run-callbacks) run-callbacks)
|
||||
(else (gnc:warn "options: bad key: " key "\n"))))
|
||||
|
||||
dispatch)
|
||||
@ -394,9 +498,10 @@
|
||||
(gnc:option-db-register-option db_handle option))
|
||||
options))
|
||||
|
||||
(define (gnc:save-options options options-string file)
|
||||
(define (gnc:save-options options options-string file header)
|
||||
(let ((code (gnc:generate-restore-forms options options-string))
|
||||
(port (open file (logior O_WRONLY O_CREAT O_TRUNC))))
|
||||
(if port (begin
|
||||
(display header port)
|
||||
(display code port)
|
||||
(close port)))))
|
||||
|
@ -1,7 +1,6 @@
|
||||
;;; $Id$
|
||||
;;;;;;;;;;; QIF Parsing ;;;;;;;;;;;;;;
|
||||
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'hash-table)
|
||||
|
||||
(define qif-txn-list '())
|
||||
|
@ -1,6 +1,5 @@
|
||||
;;;; Preferences...
|
||||
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'sort)
|
||||
(require 'hash-table)
|
||||
|
||||
@ -58,11 +57,18 @@
|
||||
(gnc:make-home-dir)
|
||||
(gnc:save-options gnc:*options-entries*
|
||||
(symbol->string 'gnc:*options-entries*)
|
||||
(build-path (getenv "HOME") ".gnucash" "config.auto")))
|
||||
(build-path (getenv "HOME") ".gnucash" "config.auto")
|
||||
(string-append
|
||||
"(gnc:config-file-format-version 1)\n\n"
|
||||
"; GnuCash Configuration Options\n")))
|
||||
|
||||
(define (gnc:config-file-format-version version) #t)
|
||||
|
||||
|
||||
;;;;;; Create default options and config vars
|
||||
|
||||
;; Account Types options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Account Types" "Show bank accounts"
|
||||
@ -119,6 +125,8 @@
|
||||
"k" "Show equity accounts in the account tree." #t))
|
||||
|
||||
|
||||
;; Account Fields options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Account Fields" "Show account name"
|
||||
@ -159,6 +167,9 @@
|
||||
"Account Fields" "Show account balance"
|
||||
"h" "Show the account balance column in the account tree." #t))
|
||||
|
||||
|
||||
;; International options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-multichoice-option
|
||||
"International" "Date Format"
|
||||
@ -166,8 +177,8 @@
|
||||
(list #(us "US" "US-style: mm/dd/yyyy")
|
||||
#(uk "UK" "UK-style dd/mm/yyyy")
|
||||
#(ce "Europe" "Continental Europe: dd.mm.yyyy")
|
||||
#(iso "ISO" "ISO Standard: yyyy-mm-dd")
|
||||
#(locale "Locale" "Take from system locale"))))
|
||||
#(iso "ISO" "ISO Standard: yyyy-mm-dd"))))
|
||||
; #(locale "Locale" "Take from system locale"))))
|
||||
|
||||
;; hack alert - we should probably get the default new account currency
|
||||
;; from the locale
|
||||
@ -182,6 +193,9 @@
|
||||
"International" "Use 24-hour time format"
|
||||
"c" "Use a 24 hour (instead of a 12 hour) time format." #f))
|
||||
|
||||
|
||||
;; Register options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-multichoice-option
|
||||
"Register" "Default Register Mode"
|
||||
@ -200,15 +214,150 @@
|
||||
"Register" "Auto-Raise Lists"
|
||||
"b" "Automatically raise the list of accounts or actions during input." #t))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Register" "Show All Transactions"
|
||||
"c" "By default, show every transaction in an account." #t))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"Register" "Number of Rows"
|
||||
"d" "Default number of register rows to display."
|
||||
15.0 ;; default
|
||||
1.0 ;; lower bound
|
||||
200.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
|
||||
;; Register Color options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Header background"
|
||||
"a" "The header background color"
|
||||
(list #xff #xff #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Single mode default even row background"
|
||||
"b" "The default background color for even rows in single mode"
|
||||
(list #xcc #xcc #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Single mode default odd row background"
|
||||
"bb" "The default background color for odd rows in single mode"
|
||||
(list #xcc #xcc #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Single mode active background"
|
||||
"c" "The background color for the active transaction in single mode"
|
||||
(list #xff #xdd #xdd 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Double mode default even row background"
|
||||
"d" "The default background color for even rows in double mode"
|
||||
(list #xcc #xcc #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Double mode default odd row background"
|
||||
"e" "The default background color for odd rows in double mode"
|
||||
(list #xff #xff #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Register Colors" "Double mode colors alternate with transactions"
|
||||
"ee" "Alternate the even and odd colors with each transaction, not each row"
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Double mode active background"
|
||||
"f" "The background color for the active transaction in double mode"
|
||||
(list #xff #xdd #xdd 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Multi mode default transaction background"
|
||||
"g" "The default background color for transactions in multi-line mode and the auto modes"
|
||||
(list #xcc #xcc #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Multi mode active transaction background"
|
||||
"h" "The background color for an active transaction in multi-line mode and the auto modes"
|
||||
(list #xff #xdd #xdd 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Multi mode default split background"
|
||||
"i" "The default background color for splits in multi-line mode and the auto modes"
|
||||
(list #xff #xff #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-color-option
|
||||
"Register Colors" "Multi mode active split background"
|
||||
"j" "The background color for an active split in multi-line mode and the auto modes"
|
||||
(list #xff #xff #xdd 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
|
||||
;; General Options
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"General" "Save Window Geometry"
|
||||
"a" "Save window sizes and positions." #t))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-multichoice-option
|
||||
"General" "Toolbar Buttons"
|
||||
"a" "Choose whether to display icons, text, or both for toolbar buttons"
|
||||
"b" "Choose whether to display icons, text, or both for toolbar buttons"
|
||||
'icons_and_text
|
||||
(list #(icons_and_text "Icons and Text" "Show both icons and text")
|
||||
#(icons_only "Icons only" "Show icons only")
|
||||
#(text_only "Text only" "Show text only"))))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-multichoice-option
|
||||
"General" "Account Separator"
|
||||
"c" "The character used to separate fully-qualified account names"
|
||||
'colon
|
||||
(list #(colon ": (Colon)" "Income:Salary:Taxable")
|
||||
#(slash "/ (Slash)" "Income/Salary/Taxable")
|
||||
#(backslash "\\ (Backslash)" "Income\\Salary\\Taxable")
|
||||
#(dash "- (Dash)" "Income-Salary-Taxable")
|
||||
#(period ". (Period)" "Income.Salary.Taxable"))))
|
||||
|
||||
|
||||
;; Configuation variables
|
||||
|
||||
(define gnc:*arg-show-version*
|
||||
(gnc:make-config-var
|
||||
"Show version."
|
||||
@ -286,3 +435,87 @@ the current value of the path."
|
||||
#f)))
|
||||
equal?
|
||||
'(default)))
|
||||
|
||||
|
||||
;; Internal options -- Section names that start with "__" are not
|
||||
;; displayed in option dialogs.
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "account_add_win_width" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "account_add_win_height" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "account_edit_win_width" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "account_edit_win_height" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "main_win_width" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "main_win_height" #f #f
|
||||
400.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "reg_win_width" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
||||
(gnc:register-configuration-option
|
||||
(gnc:make-number-range-option
|
||||
"__gui" "reg_stock_win_width" #f #f
|
||||
0.0 ;; default
|
||||
0.0 ;; lower bound
|
||||
32000.0 ;; upper bound
|
||||
0.0 ;; number of decimals
|
||||
1.0 ;; step size
|
||||
))
|
||||
|
@ -1,4 +1,3 @@
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'hash-table)
|
||||
|
||||
(gnc:support "report.scm")
|
||||
@ -46,17 +45,25 @@
|
||||
(call-report rendering-thunk options)))))
|
||||
|
||||
(define (gnc:report-menu-setup win)
|
||||
;; This should be on a reports menu later...
|
||||
|
||||
(define menu (gnc:make-menu "_Reports" (list "_Settings")))
|
||||
(define menu-namer (gnc:new-menu-namer))
|
||||
|
||||
(gnc:add-extension menu)
|
||||
|
||||
(hash-for-each
|
||||
(lambda (name report)
|
||||
(gnc:extensions-menu-add-item
|
||||
(string-append "Report: " name)
|
||||
(define item
|
||||
(gnc:make-menu-item
|
||||
((menu-namer 'add-name) name)
|
||||
(string-append "Display the " name " report.")
|
||||
(list "_Reports" "")
|
||||
(lambda ()
|
||||
(let ((options (false-if-exception (gnc:report-new-options report))))
|
||||
(gnc:report-window (string-append "Report: " name)
|
||||
(lambda () (gnc:run-report name options))
|
||||
options)))))
|
||||
(gnc:add-extension item))
|
||||
*gnc:_report-info_*))
|
||||
|
||||
(define (gnc:define-report version name option-generator rendering-thunk)
|
||||
|
@ -1,43 +1,56 @@
|
||||
;; -*-scheme-*-
|
||||
;; average-balance.scm
|
||||
;; Report history of account balance and other info
|
||||
;; Also graphs the information with gnuplot
|
||||
;; Matt Martin <mgmartin@abacusnet.net>
|
||||
;; Plots the information with gnuplot
|
||||
;;
|
||||
;; Author makes no implicit or explicit guarantee of accuracy of
|
||||
;; these calculations and accepts no responsibility for direct
|
||||
;; or indirect losses incurred as a result of using this software.
|
||||
;;
|
||||
;; Note that this code uses functions defined in "transaction-report.scm"
|
||||
;; Matt Martin <matt.martin@ieee.org>
|
||||
|
||||
(use-modules (ice-9 slib)(ice-9 regex))
|
||||
(use-modules (ice-9 regex))
|
||||
(require 'hash-table)
|
||||
(require 'printf)
|
||||
|
||||
;hack alert - is this line necessary?
|
||||
(gnc:depend "text-export.scm")
|
||||
(gnc:depend "structure.scm")
|
||||
|
||||
(define datelist '())
|
||||
|
||||
;; Add delta to date, return result
|
||||
(define (incdate adate delta)
|
||||
;; Modify a date
|
||||
(define (moddate op adate delta)
|
||||
(let ((newtm (localtime (car adate))))
|
||||
(begin
|
||||
(set-tm:mday newtm (+ (tm:mday newtm) (tm:mday delta)))
|
||||
(set-tm:mon newtm (+ (tm:mon newtm) (tm:mon delta)))
|
||||
(set-tm:year newtm (+ (tm:year newtm) (tm:year delta)))
|
||||
(set-tm:sec newtm (op (tm:sec newtm) (tm:sec delta)))
|
||||
(set-tm:min newtm (op (tm:min newtm) (tm:min delta)))
|
||||
(set-tm:hour newtm (op (tm:hour newtm) (tm:hour delta)))
|
||||
(set-tm:mday newtm (op (tm:mday newtm) (tm:mday delta)))
|
||||
(set-tm:mon newtm (op (tm:mon newtm) (tm:mon delta)))
|
||||
(set-tm:year newtm (op (tm:year newtm) (tm:year delta)))
|
||||
|
||||
(let ((time (car (mktime newtm))))
|
||||
(cons time 0))
|
||||
))
|
||||
)
|
||||
|
||||
;; actual recursion for date list building
|
||||
;; Add or subtract time from a date
|
||||
(define (decdate adate delta)(moddate - adate delta ))
|
||||
(define (incdate adate delta)(moddate + adate delta ))
|
||||
|
||||
;; Time comparison, true if t2 is later than t1
|
||||
(define (gnc:timepair-later t1 t2)
|
||||
(< (car t1) (car t2)))
|
||||
|
||||
;; Build a list of time intervals
|
||||
(define (dateloop curd endd incr)
|
||||
(cond ((gnc:timepair-later-date curd endd)
|
||||
(cons curd (dateloop (incdate curd incr) endd incr)))
|
||||
(else (list curd))
|
||||
(cond ((gnc:timepair-later curd endd)
|
||||
(let ((nextd (incdate curd incr)))
|
||||
(cons (list curd (decdate nextd SecDelta) '())
|
||||
(dateloop nextd endd incr))))
|
||||
(else '())
|
||||
)
|
||||
)
|
||||
|
||||
;; Create list of dates to report on
|
||||
(define (generate-datelist beg nd stp)
|
||||
(set! datelist (dateloop beg nd (eval stp))))
|
||||
|
||||
;; Options
|
||||
(define (runavg-options-generator)
|
||||
(define gnc:*runavg-track-options* (gnc:new-options))
|
||||
|
||||
@ -78,12 +91,24 @@
|
||||
"d" "Do transaction report on this account"
|
||||
(lambda ()
|
||||
(let ((current-accounts (gnc:get-current-accounts))
|
||||
(num-accounts (gnc:group-get-num-accounts (gnc:get-current-group)))
|
||||
(first-account (gnc:group-get-account (gnc:get-current-group) 0)))
|
||||
(cond ((not (null? current-accounts)) (list (car current-accounts)))
|
||||
((> num-accounts 0) (list first-account))
|
||||
(else ()))))
|
||||
#f #f))
|
||||
(num-accounts
|
||||
(gnc:group-get-num-accounts (gnc:get-current-group))))
|
||||
|
||||
(cond ((not (null? current-accounts)) current-accounts)
|
||||
(else
|
||||
(let ((acctlist '()))
|
||||
(gnc:for-loop
|
||||
(lambda(x)
|
||||
(set! acctlist
|
||||
(append!
|
||||
acctlist
|
||||
(list (gnc:group-get-account
|
||||
(gnc:get-current-group) x)))))
|
||||
0 (eval num-accounts) 1)
|
||||
acctlist
|
||||
)
|
||||
))))
|
||||
#f #t))
|
||||
|
||||
(gnc:register-runavg-option
|
||||
(gnc:make-multichoice-option
|
||||
@ -96,10 +121,15 @@
|
||||
#(YearDelta "Year" "Year")
|
||||
)))
|
||||
|
||||
(gnc:register-runavg-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Report Options" "Sub-Accounts"
|
||||
"e" "Add in sub-accounts of each selected" #f))
|
||||
|
||||
(gnc:register-runavg-option
|
||||
(gnc:make-multichoice-option
|
||||
"Report Options" "Plot Type"
|
||||
"b" "Get number at each one of these" 'NoPlot
|
||||
"f" "Get number at each one of these" 'NoPlot
|
||||
(list #(NoPlot "Nothing" "Make No Plot")
|
||||
#(AvgBalPlot "Average" "Average Balance")
|
||||
#(GainPlot "Net Gain" "Net Gain")
|
||||
@ -121,6 +151,9 @@
|
||||
zd
|
||||
))
|
||||
|
||||
(define SecDelta (let ((ddt (eval zdate)))
|
||||
(set-tm:sec ddt 1)
|
||||
ddt))
|
||||
(define YearDelta (let ((ddt (eval zdate)))
|
||||
(set-tm:year ddt 1)
|
||||
ddt))
|
||||
@ -139,12 +172,13 @@
|
||||
(set-tm:mon ddt 1)
|
||||
ddt))
|
||||
|
||||
(define AvgBalPlot "using 1:2:3:4 t 'Average Balance' with errorbars")
|
||||
(define GainPlot "using 1:5 t 'Net Gain' with linespoints")
|
||||
(define GLPlot "using 1:7 t 'Losses' with lp, '' using 1:6 t 'Gains' with lp")
|
||||
;; Plot strings
|
||||
(define AvgBalPlot "using 2:3:4:5 t 'Average Balance' with errorbars, '' using 2:3 smooth sbezier t '' with lines")
|
||||
(define GainPlot "using 2:6 t 'Net Gain' with linespoints, '' using 2:6 smooth sbezier t '' with lines" )
|
||||
(define GLPlot "using 2:8 t 'Losses' with lp, '' using 2:7 t 'Gains' with lp")
|
||||
(define NoPlot "")
|
||||
|
||||
;;; applies thunk to each split in account account
|
||||
;; applies thunk to each split in account account
|
||||
(define (gnc:for-each-split-in-account account thunk)
|
||||
(gnc:for-loop (lambda (x) (thunk (gnc:account-get-split account x)))
|
||||
0 (gnc:account-get-split-count account) 1))
|
||||
@ -163,30 +197,14 @@
|
||||
(define (gnc:split-get-account-name split)
|
||||
(gnc:account-get-name (gnc:split-get-account split)))
|
||||
|
||||
;; timepair manipulation functions
|
||||
;; hack alert - these should probably be put somewhere else
|
||||
;; and be implemented PROPERLY rather than hackily
|
||||
|
||||
(define (gnc:timepair-to-datestring tp)
|
||||
(define (gnc:timepair-to-ldatestring tp)
|
||||
(let ((bdtime (localtime (car tp))))
|
||||
(strftime "%m/%d/%Y" bdtime)))
|
||||
|
||||
|
||||
;; Find difference in seconds (?) between time 1 and time2
|
||||
(define (gnc:timepair-delta t1 t2)
|
||||
(let ((time1 (car (gnc:timepair-canonical-day-time t1)))
|
||||
(time2 (car (gnc:timepair-canonical-day-time t2))))
|
||||
(- time2 time1)))
|
||||
|
||||
;; Don't know if these can be local+static to reduce-split-list
|
||||
(define tempmax -1E10)
|
||||
(define tempmin 1E10)
|
||||
(define last 0)
|
||||
(define zdate (cons 0 0))
|
||||
(define prevdate zdate)
|
||||
(define avgaccum 0)
|
||||
(define lossaccum 0)
|
||||
(define gainaccum 0)
|
||||
(- (car t2) (car t1)))
|
||||
|
||||
; Convert to string
|
||||
(define (tostring val)
|
||||
@ -205,11 +223,13 @@
|
||||
|
||||
; Create an html table row from a list of entries
|
||||
(define (html-table-row lst)
|
||||
(cond ((string? lst) lst)
|
||||
(else
|
||||
(string-append
|
||||
(sprintf #f "<TR>")
|
||||
(apply string-append (map html-table-col lst))
|
||||
(sprintf #f "</TR>\n")
|
||||
)
|
||||
)))
|
||||
)
|
||||
|
||||
; Create an html table from a list of rows, each containing
|
||||
@ -227,7 +247,7 @@
|
||||
)
|
||||
|
||||
(define (html-table-header vec)
|
||||
(apply string-append "<TABLE cellspacing=10>" (map html-table-headcol vec))
|
||||
(apply string-append "<TABLE cellspacing=10 rules=\"rows\">\n" (map html-table-headcol vec))
|
||||
)
|
||||
|
||||
(define (html-table-footer)
|
||||
@ -274,89 +294,199 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; Reset accumulators between time intervals
|
||||
(define (resetvals bal curdate)
|
||||
(set! tempmax bal)
|
||||
(set! tempmin bal)
|
||||
(set! prevdate curdate)
|
||||
(set! avgaccum 0)
|
||||
(set! lossaccum 0)
|
||||
(set! gainaccum 0)
|
||||
)
|
||||
;; Returns sum of all vector elements after the first
|
||||
(define (vector-sum v)
|
||||
(let ((sum 0))
|
||||
(gnc:for-loop (lambda(i) (set! sum (+ sum (car (vector-ref v i)))))
|
||||
1 (vector-length v) 1)
|
||||
sum))
|
||||
|
||||
;
|
||||
; Reduce a list of splits tl to a list of values at each date in datelist dl
|
||||
;
|
||||
(define (reduce-split-list dl tl pt)
|
||||
; Datelist entry operators
|
||||
(define (dl:begin dl) (car dl))
|
||||
(define (dl:end dl) (car (cdr dl)))
|
||||
|
||||
(define (reduce-split-list dl tl pt av)
|
||||
(let ((avgaccum 0)
|
||||
(bals av)
|
||||
(prevdate 0)
|
||||
(balmin 10E9)
|
||||
(balmax -10E9)
|
||||
(gains 0)
|
||||
(losses 0))
|
||||
|
||||
(define (procvals)
|
||||
(let ((curbal (vector-sum (car (cdr (av 'x 0))))))
|
||||
(set! balmin (min balmin curbal))
|
||||
(set! balmax (max balmax curbal))))
|
||||
|
||||
(define (accbal beg end)
|
||||
(let ((curbal (vector-sum (car (cdr (av 'x 0))))))
|
||||
(set! avgaccum (+ avgaccum
|
||||
(* curbal
|
||||
(gnc:timepair-delta beg end)))))
|
||||
)
|
||||
|
||||
|
||||
(define (calc-in-interval d tl)
|
||||
(cond ((not (null? tl))
|
||||
|
||||
(let* ((bd (dl:begin d)) ; begin date
|
||||
(ed (dl:end d)) ; end date
|
||||
(cs (car tl)) ; current split
|
||||
(cd (gnc:split-get-transaction-date cs)) ;current date
|
||||
(an (gnc:split-get-account-name cs)) ; account name
|
||||
(prevbal (vector-sum (car (cdr (av 'x 0))))))
|
||||
|
||||
(cond ((gnc:timepair-later cd bd) ;split before interval
|
||||
(bals 'put an (gnc:split-get-balance cs))
|
||||
(calc-in-interval d (cdr tl))
|
||||
)
|
||||
|
||||
((gnc:timepair-later cd ed) ;split is in the interval
|
||||
(accbal prevdate cd)
|
||||
(procvals)
|
||||
(bals 'put an (gnc:split-get-balance cs))
|
||||
|
||||
(let ((val (gnc:split-get-value cs)))
|
||||
(cond ((< 0 val) (set! gains (+ gains val)))
|
||||
(else (set! losses (- losses val)))))
|
||||
|
||||
(procvals) ; catch all cases
|
||||
(set! prevdate cd)
|
||||
(calc-in-interval d (cdr tl))
|
||||
)
|
||||
|
||||
(else ; Past interval, nothing to do?
|
||||
(accbal prevdate ed)
|
||||
(procvals)
|
||||
tl
|
||||
)
|
||||
)))
|
||||
|
||||
(else ; Out of data !
|
||||
(accbal prevdate (dl:end d))
|
||||
(procvals)
|
||||
tl
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; Actual routine
|
||||
(cond ((null? dl) '()) ;; End of recursion
|
||||
|
||||
(else (let* ((bal last) ;; get Balance and datelist "time"
|
||||
(ct (car dl))
|
||||
(val 0))
|
||||
|
||||
(begin
|
||||
(cond ( (not (null? tl))
|
||||
;; Get latest split values if any remain
|
||||
(set! bal (gnc:split-get-balance (car tl)))
|
||||
(set! val (gnc:split-get-value (car tl)))
|
||||
(set! ct (gnc:split-get-transaction-date (car tl)))
|
||||
))
|
||||
|
||||
(cond ; past time interval bound ?
|
||||
((or(gnc:timepair-later-date (car dl) ct ) (null? tl))
|
||||
|
||||
(cond ; Is this the first interval ?
|
||||
((= (car zdate) (car prevdate) )
|
||||
; Start first date interval
|
||||
(begin
|
||||
(resetvals bal (car dl))
|
||||
(reduce-split-list (cdr dl) tl (car dl))
|
||||
)
|
||||
)
|
||||
(else
|
||||
(set! avgaccum ; sum up to now
|
||||
(+ avgaccum
|
||||
(* last (gnc:timepair-delta pt (car dl)))))
|
||||
(let* ((bd (dl:begin (car dl)))
|
||||
(ed (dl:end (car dl))) )
|
||||
|
||||
(cons ; form list of values for one "row"
|
||||
;; 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-datestring (car dl))
|
||||
(let ((dlta (gnc:timepair-delta prevdate (car dl))))
|
||||
(cond ((= dlta 0) 0); Should never happen !
|
||||
((= avgaccum 0) bal)
|
||||
(else (/ avgaccum dlta))))
|
||||
tempmax
|
||||
tempmin
|
||||
(- gainaccum lossaccum)
|
||||
gainaccum
|
||||
lossaccum
|
||||
)
|
||||
(begin
|
||||
(resetvals last (car dl))
|
||||
(reduce-split-list (cdr dl) tl (car dl))
|
||||
(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)))
|
||||
)
|
||||
)
|
||||
)))
|
||||
(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)
|
||||
))
|
||||
)
|
||||
)))))
|
||||
|
||||
;; Pull a scheme list of splits from a C array
|
||||
(define (gnc:convert-split-list slist)
|
||||
(let ((numsplit 0)
|
||||
(schsl '()))
|
||||
(while
|
||||
(let ((asplit (gnc:ith-split slist numsplit)))
|
||||
(cond
|
||||
((pointer-token-null? asplit ) #f)
|
||||
(else
|
||||
(set! schsl (append! schsl (list asplit)) )
|
||||
(set! numsplit (+ numsplit 1))
|
||||
#t))) ())
|
||||
schsl
|
||||
)
|
||||
)
|
||||
|
||||
;; Pull a scheme list of accounts (including subaccounts) from group grp
|
||||
(define (gnc:group-get-account-list grp)
|
||||
(cond ((pointer-token-null? grp) '())
|
||||
(else
|
||||
(let ((numacct 0)
|
||||
(acctar (gnc:get-accounts grp))
|
||||
(schal '()))
|
||||
|
||||
(while
|
||||
(let ((anact (gnc:account-nth-account acctar numacct)))
|
||||
(cond
|
||||
((pointer-token-null? anact ) #f)
|
||||
(else
|
||||
(set! schal (append! schal (list anact)) )
|
||||
(set! numacct (+ numacct 1))
|
||||
#t))) ())
|
||||
schal
|
||||
)))
|
||||
)
|
||||
|
||||
(define (accumvects x y)
|
||||
(cond
|
||||
((null? x) '())
|
||||
((number? (car x))
|
||||
(cons (+ (car x) (car y)) (accumvects (cdr x) (cdr y))))
|
||||
(else (cons "x" (accumvects (cdr x) (cdr y)))))
|
||||
)
|
||||
|
||||
;; Add x to list lst if it is not already in there
|
||||
(define (addunique lst x)
|
||||
(cond
|
||||
((null? lst) (list x)) ; all checked add it
|
||||
(else (cond
|
||||
((equal? x (car lst)) lst) ; found, quit search and don't add again
|
||||
(else (cons (car lst) (addunique (cdr lst) x))) ; keep searching
|
||||
))))
|
||||
|
||||
;; Calculate averages of each column
|
||||
(define (get-averages indata)
|
||||
(let* ((avglst '()))
|
||||
|
||||
(map (lambda (x) (set! avglst (append avglst (list 0.0)))) (car indata))
|
||||
|
||||
(map (lambda (x)
|
||||
|
||||
(set! avglst (accumvects x avglst)))
|
||||
indata)
|
||||
(map (lambda (x)
|
||||
(cond ((number? x) (/ x (length indata)))
|
||||
(else "")))
|
||||
avglst)
|
||||
))
|
||||
|
||||
;; Turn a C array of accounts into a scheme list of account names
|
||||
(define (gnc:acctnames-from-list acctlist)
|
||||
(let ((anlist '()))
|
||||
(map (lambda(an)
|
||||
(set! anlist (append! anlist
|
||||
(list (gnc:account-get-name an))))) acctlist)
|
||||
anlist))
|
||||
|
||||
(define acctcurrency "USD")
|
||||
(define acctname "")
|
||||
|
||||
(define (allsubaccounts accounts)
|
||||
(cond ((null? accounts) '())
|
||||
(else
|
||||
; (display (gnc:account-get-name (car accounts)))(newline)
|
||||
(append
|
||||
(gnc:group-get-account-list
|
||||
(gnc:account-get-children (car accounts)))
|
||||
(allsubaccounts (cdr accounts))))))
|
||||
|
||||
(gnc:define-report
|
||||
;; version
|
||||
1
|
||||
@ -369,8 +499,10 @@
|
||||
(let* (
|
||||
(begindate (gnc:option-value
|
||||
(gnc:lookup-option options "Report Options" "From")))
|
||||
(enddate (gnc:lookup-option options "Report Options" "To"))
|
||||
(stepsize (gnc:lookup-option options "Report Options" "Step Size"))
|
||||
(enddate (gnc:option-value
|
||||
(gnc:lookup-option options "Report Options" "To")))
|
||||
(stepsize (gnc:option-value
|
||||
(gnc:lookup-option options "Report Options" "Step Size")))
|
||||
|
||||
(plotstr (gnc:option-value
|
||||
(gnc:lookup-option options "Report Options" "Plot Type")))
|
||||
@ -378,45 +510,94 @@
|
||||
(accounts (gnc:option-value
|
||||
(gnc:lookup-option options
|
||||
"Report Options" "Account")))
|
||||
|
||||
(dosubs (gnc:option-value
|
||||
(gnc:lookup-option options
|
||||
"Report Options" "Sub-Accounts")))
|
||||
|
||||
(prefix (list "<HTML>" "<BODY>"))
|
||||
(suffix (list "</BODY>" "</HTML>"))
|
||||
(collist
|
||||
(list "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss"))
|
||||
(list "Beginning" "Ending" "Average" "Max" "Min" "Net Gain" "Gain" "Loss"))
|
||||
|
||||
(report-lines '())
|
||||
(rept-data '())
|
||||
(sum-data '())
|
||||
(tempstruct '())
|
||||
(rept-text "")
|
||||
(gncq (gnc:malloc-query))
|
||||
|
||||
(slist '())
|
||||
|
||||
)
|
||||
|
||||
|
||||
(generate-datelist
|
||||
begindate
|
||||
(gnc:option-value enddate)
|
||||
(gnc:option-value stepsize))
|
||||
(gnc:init-query gncq)
|
||||
|
||||
(if (null? accounts)
|
||||
(set! report-lines
|
||||
(list "<TR><TD>You have not selected an account.</TD></TR>"))
|
||||
(begin
|
||||
; Grab account names
|
||||
(set! acctname (gnc:account-get-name (car accounts)))
|
||||
(map (lambda(an)
|
||||
(set! acctname
|
||||
(string-append
|
||||
acctname
|
||||
" , "
|
||||
(gnc:account-get-name an))))
|
||||
(cdr accounts) )
|
||||
|
||||
(cond ((equal? dosubs #t)
|
||||
(map (lambda (a)
|
||||
(set! accounts (addunique accounts a)))
|
||||
(allsubaccounts accounts))
|
||||
|
||||
(set! acctname (string-append acctname " and sub-accounts"))
|
||||
))
|
||||
|
||||
(map (lambda(acct) (gnc:query-add-account gncq acct)) accounts)
|
||||
|
||||
(set! tempstruct
|
||||
(build-mystruct-instance
|
||||
(define-mystruct
|
||||
(gnc:acctnames-from-list accounts))))
|
||||
|
||||
(set! acctcurrency (gnc:account-get-currency (car accounts)))
|
||||
(gnc:for-each-split-in-account
|
||||
(car accounts)
|
||||
(lambda (split)
|
||||
|
||||
(set! report-lines
|
||||
(append! report-lines (list split)))))))
|
||||
(gnc:convert-split-list (gnc:query-get-splits gncq)))))
|
||||
|
||||
(gnc:free-query gncq)
|
||||
|
||||
(display (length report-lines))
|
||||
(display " Splits\n")
|
||||
(set! prevdate zdate)
|
||||
(set! rept-data (reduce-split-list datelist report-lines (car datelist)))
|
||||
|
||||
; Set initial balances to zero
|
||||
(map (lambda(an) (tempstruct 'put an 0))
|
||||
(gnc:acctnames-from-list accounts))
|
||||
|
||||
(dateloop begindate
|
||||
enddate
|
||||
(eval stepsize))
|
||||
(set! rept-data
|
||||
(reduce-split-list
|
||||
(dateloop begindate
|
||||
enddate
|
||||
(eval stepsize))
|
||||
report-lines zdate tempstruct))
|
||||
|
||||
(set! sum-data (get-averages rept-data))
|
||||
|
||||
|
||||
;; Create HTML
|
||||
(set! rept-text
|
||||
(html-table
|
||||
collist
|
||||
rept-data))
|
||||
(append rept-data
|
||||
(list "<TR cellspacing=0><TD><TD><TD colspan=3><HR size=2 noshade><TD colspan=3><HR size=2 noshade></TR>" sum-data))))
|
||||
|
||||
|
||||
;; Do a plot
|
||||
(if (not (equal? NoPlot (eval plotstr)))
|
||||
(let* ((fn "/tmp/gncplot.dat")
|
||||
(preplot (string-append
|
||||
@ -435,6 +616,6 @@
|
||||
(string-append "echo \"" preplot "plot '" fn "'" (eval plotstr)
|
||||
"\"|gnuplot -persist " )))
|
||||
)
|
||||
|
||||
(append prefix (list rept-text) suffix)))
|
||||
(append prefix (list "Report for " acctname "<p>\n" )
|
||||
(list rept-text) suffix)))
|
||||
)
|
||||
|
@ -1,8 +1,5 @@
|
||||
;; -*-scheme-*-
|
||||
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'stdio)
|
||||
|
||||
(gnc:depend "text-export.scm")
|
||||
|
||||
(let ()
|
||||
|
@ -1,27 +1,27 @@
|
||||
|
||||
;; I haven't finished converting this yet...
|
||||
|
||||
(gnc:define-report
|
||||
;(gnc:define-report
|
||||
;; version
|
||||
1
|
||||
; 1
|
||||
;; Menu name
|
||||
"Folio"
|
||||
; "Folio"
|
||||
;; Options Generator
|
||||
#f
|
||||
; #f
|
||||
;; Rendering thunk. See report.scm for details.
|
||||
(lambda (options)
|
||||
(list
|
||||
"<html>"
|
||||
"<head>"
|
||||
"<title>Portfolio Valuation</title>"
|
||||
"</head>"
|
||||
; (lambda (options)
|
||||
; (list
|
||||
; "<html>"
|
||||
; "<head>"
|
||||
; "<title>Portfolio Valuation</title>"
|
||||
; "</head>"
|
||||
|
||||
"<body bgcolor=#ccccff>"
|
||||
"This page shows the valuation of your stock/mutual fund portfolio."
|
||||
"<br>"
|
||||
"You can create custom reports by editing the file"
|
||||
"<tt>Reports/report-folio.phtml</tt>"
|
||||
"<p>"
|
||||
; "<body bgcolor=#ccccff>"
|
||||
; "This page shows the valuation of your stock/mutual fund portfolio."
|
||||
; "<br>"
|
||||
; "You can create custom reports by editing the file"
|
||||
; "<tt>Reports/report-folio.phtml</tt>"
|
||||
; "<p>"
|
||||
|
||||
;; currency symbol that is printed is a dollar sign, for now
|
||||
;; currency amounts get printed with two decimal places
|
||||
@ -34,130 +34,125 @@
|
||||
;; This rouine accepts a pointer to a group, returns
|
||||
;; a flat list of all of the children in the group.
|
||||
|
||||
sub account_flatlist
|
||||
{
|
||||
local ($grp) = $_[0];
|
||||
local ($naccts) = gnucash::xaccGroupGetNumAccounts ($grp);
|
||||
local ($n);
|
||||
local (@acctlist, @childlist);
|
||||
local ($children);
|
||||
;sub account_flatlist
|
||||
;{
|
||||
; local ($grp) = $_[0];
|
||||
; local ($naccts) = gnucash::xaccGroupGetNumAccounts ($grp);
|
||||
; local ($n);
|
||||
; local (@acctlist, @childlist);
|
||||
; local ($children);
|
||||
|
||||
foreach $n (0..$naccts-1) {
|
||||
$acct = gnucash::xaccGroupGetAccount ($grp, $n);
|
||||
push (@acctlist, $acct);
|
||||
$children = gnucash::xaccAccountGetChildren ($acct);
|
||||
if ($children) {
|
||||
@childlist = &account_flatlist ($children);
|
||||
push (@acctlist, @childlist);
|
||||
}
|
||||
}
|
||||
; foreach $n (0..$naccts-1) {
|
||||
; $acct = gnucash::xaccGroupGetAccount ($grp, $n);
|
||||
; push (@acctlist, $acct);
|
||||
; $children = gnucash::xaccAccountGetChildren ($acct);
|
||||
; if ($children) {
|
||||
; @childlist = &account_flatlist ($children);
|
||||
; push (@acctlist, @childlist);
|
||||
; }
|
||||
; }
|
||||
|
||||
return (@acctlist);
|
||||
}
|
||||
; return (@acctlist);
|
||||
;}
|
||||
|
||||
;; --------------------------------------------------
|
||||
;; $split = &get_last_split ($account);
|
||||
;; returns the most recent split in the account.
|
||||
|
||||
sub get_last_split
|
||||
{
|
||||
local ($acct) = $_[0];
|
||||
local ($query, $splitlist, $split);
|
||||
;sub get_last_split
|
||||
;{
|
||||
; local ($acct) = $_[0];
|
||||
; local ($query, $splitlist, $split);
|
||||
|
||||
$query = gnucash::xaccMallocQuery();
|
||||
gnucash::xaccQueryAddAccount ($query, $acct);
|
||||
gnucash::xaccQuerySetMaxSplits ($query, 1);
|
||||
$splitlist = gnucash::xaccQueryGetSplits ($query);
|
||||
; $query = gnucash::xaccMallocQuery();
|
||||
; gnucash::xaccQueryAddAccount ($query, $acct);
|
||||
; gnucash::xaccQuerySetMaxSplits ($query, 1);
|
||||
; $splitlist = gnucash::xaccQueryGetSplits ($query);
|
||||
|
||||
$split = gnucash::IthSplit ($splitlist, 0);
|
||||
}
|
||||
; $split = gnucash::IthSplit ($splitlist, 0);
|
||||
;}
|
||||
|
||||
;; --------------------------------------------------
|
||||
|
||||
;; get a flat list of all the accounts ...
|
||||
@acclist = &account_flatlist ($topgroup);
|
||||
;@acclist = &account_flatlist ($topgroup);
|
||||
|
||||
;; get the most recent price date ..
|
||||
$latest = -1.0e20;
|
||||
$earliest = 1.0e20;
|
||||
foreach $acct (@acclist)
|
||||
{
|
||||
$accntype = &gnucash::xaccAccountGetType($acct);
|
||||
if (($accntype == $gnucash::STOCK) ||
|
||||
($accntype == $gnucash::MUTUAL)) {
|
||||
$split = &get_last_split ($acct);
|
||||
$trans = gnucash::xaccSplitGetParent ($split);
|
||||
$secs = gnucash::xaccTransGetDate ($trans);
|
||||
if ($latest < $secs) { $latest = $secs; }
|
||||
if ($earliest > $secs) { $earliest = $secs; }
|
||||
}
|
||||
}
|
||||
;$latest = -1.0e20;
|
||||
;$earliest = 1.0e20;
|
||||
;foreach $acct (@acclist)
|
||||
;{
|
||||
; $accntype = &gnucash::xaccAccountGetType($acct);
|
||||
; if (($accntype == $gnucash::STOCK) ||
|
||||
; ($accntype == $gnucash::MUTUAL)) {
|
||||
; $split = &get_last_split ($acct);
|
||||
; $trans = gnucash::xaccSplitGetParent ($split);
|
||||
; $secs = gnucash::xaccTransGetDate ($trans);
|
||||
; if ($latest < $secs) { $latest = $secs; }
|
||||
; if ($earliest > $secs) { $earliest = $secs; }
|
||||
; }
|
||||
;}
|
||||
|
||||
$ldayte = gnucash::xaccPrintDateSecs ($latest);
|
||||
$edayte = gnucash::xaccPrintDateSecs ($earliest);
|
||||
;$ldayte = gnucash::xaccPrintDateSecs ($latest);
|
||||
;$edayte = gnucash::xaccPrintDateSecs ($earliest);
|
||||
|
||||
:>
|
||||
|
||||
<table cellpadding=1>
|
||||
<caption><b>Stock Portfolio Valuation</b>
|
||||
<br>Earliest Price <:= $edayte :> Latest Price <:= $ldayte :>
|
||||
</caption>
|
||||
<tr>
|
||||
<th>Name
|
||||
<th>Ticker
|
||||
<th align=center>Shares
|
||||
<th align=center>Recent Price
|
||||
<th align=center>Value
|
||||
<th align=center>Cost
|
||||
<th align=center>Profit/Loss
|
||||
;<table cellpadding=1>
|
||||
;<caption><b>Stock Portfolio Valuation</b>
|
||||
;<br>Earliest Price <:= $edayte :> Latest Price <:= $ldayte :>
|
||||
;</caption>
|
||||
;<tr>
|
||||
;<th>Name
|
||||
;<th>Ticker
|
||||
;<th align=center>Shares
|
||||
;<th align=center>Recent Price
|
||||
;<th align=center>Value
|
||||
;<th align=center>Cost
|
||||
;<th align=center>Profit/Loss
|
||||
|
||||
<:
|
||||
;$totvalue = 0;
|
||||
;$totcost = 0;
|
||||
|
||||
$totvalue = 0;
|
||||
$totcost = 0;
|
||||
;foreach $acct (@acclist)
|
||||
;{
|
||||
|
||||
foreach $acct (@acclist)
|
||||
{
|
||||
; $accntype = &gnucash::xaccAccountGetType($acct);
|
||||
; if (($accntype == $gnucash::STOCK) ||
|
||||
; ($accntype == $gnucash::MUTUAL)) {
|
||||
|
||||
$accntype = &gnucash::xaccAccountGetType($acct);
|
||||
if (($accntype == $gnucash::STOCK) ||
|
||||
($accntype == $gnucash::MUTUAL)) {
|
||||
; $accname = &gnucash::xaccAccountGetName($acct);
|
||||
; $ticker = &gnucash::xaccAccountGetSecurity ($acct);
|
||||
; $accbaln = &gnucash::xaccAccountGetBalance($acct);
|
||||
|
||||
$accname = &gnucash::xaccAccountGetName($acct);
|
||||
$ticker = &gnucash::xaccAccountGetSecurity ($acct);
|
||||
$accbaln = &gnucash::xaccAccountGetBalance($acct);
|
||||
; $split = &get_last_split ($acct);
|
||||
; $price = gnucash::xaccSplitGetSharePrice ($split);
|
||||
; $shares = gnucash::xaccSplitGetShareBalance ($split);
|
||||
; $value = gnucash::xaccSplitGetBalance ($split);
|
||||
; $cost = gnucash::xaccSplitGetCostBasis ($split);
|
||||
; $profit = $accbaln - $cost;
|
||||
|
||||
$split = &get_last_split ($acct);
|
||||
$price = gnucash::xaccSplitGetSharePrice ($split);
|
||||
$shares = gnucash::xaccSplitGetShareBalance ($split);
|
||||
$value = gnucash::xaccSplitGetBalance ($split);
|
||||
$cost = gnucash::xaccSplitGetCostBasis ($split);
|
||||
$profit = $accbaln - $cost;
|
||||
; $totvalue += $value;
|
||||
; $totcost += $cost;
|
||||
|
||||
$totvalue += $value;
|
||||
$totcost += $cost;
|
||||
; print "<tr><td>$accname";
|
||||
; print "<td>$ticker";
|
||||
; printf "<td align=right nowrap>%10.3f", $shares;
|
||||
; printf "<td align=right nowrap>\$%10.2f\n", $price;
|
||||
; printf "<td align=right nowrap>\$%10.2f\n", $value;
|
||||
; printf "<td align=right nowrap>\$%10.2f\n", $cost;
|
||||
; printf "<td align=right nowrap>\$%10.2f\n", $profit;
|
||||
; }
|
||||
;}
|
||||
|
||||
print "<tr><td>$accname";
|
||||
print "<td>$ticker";
|
||||
printf "<td align=right nowrap>%10.3f", $shares;
|
||||
printf "<td align=right nowrap>\$%10.2f\n", $price;
|
||||
printf "<td align=right nowrap>\$%10.2f\n", $value;
|
||||
printf "<td align=right nowrap>\$%10.2f\n", $cost;
|
||||
printf "<td align=right nowrap>\$%10.2f\n", $profit;
|
||||
}
|
||||
}
|
||||
;print "<tr><td> <td> <td> \n"; ;; blank line
|
||||
;print "<td> <td> <td> \n"; ;; blank line
|
||||
|
||||
print "<tr><td> <td> <td> \n"; ;; blank line
|
||||
print "<td> <td> <td> \n"; ;; blank line
|
||||
;print "<tr><td><b>Net</b><td> ";
|
||||
;print "<td> <td> ";
|
||||
;printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totvalue;
|
||||
;printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totcost;
|
||||
;printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totvalue-$totcost;
|
||||
|
||||
print "<tr><td><b>Net</b><td> ";
|
||||
print "<td> <td> ";
|
||||
printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totvalue;
|
||||
printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totcost;
|
||||
printf "<td align=right nowrap> <u>\$%10.2f</u> \n", $totvalue-$totcost;
|
||||
|
||||
:>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
;</table>
|
||||
;</body>
|
||||
;</html>
|
||||
|
@ -21,7 +21,7 @@
|
||||
(define (gnc:register-dummy-option new-option)
|
||||
(gnc:register-option gnc:*dummy-options* new-option))
|
||||
|
||||
;; This is a boolean option. It is in Section 'Page One'
|
||||
;; This is a boolean option. It is in Section 'Hello, World!'
|
||||
;; and is named 'Boolean Option'. Its sorting key is 'a',
|
||||
;; thus it will come before options with sorting keys
|
||||
;; 'b', 'c', etc. in the same section. The default value
|
||||
@ -30,7 +30,7 @@
|
||||
;; the mouse pointer over the option.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Page One" "Boolean Option"
|
||||
"Hello, World!" "Boolean Option"
|
||||
"a" "This is a boolean option." #t))
|
||||
|
||||
;; This is a multichoice option. The user can choose between
|
||||
@ -40,8 +40,8 @@
|
||||
;; value is 'third.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-multichoice-option
|
||||
"Page Two" "Multi Choice Option"
|
||||
"a" "This is a multi choice option." 'third
|
||||
"Hello, World!" "Multi Choice Option"
|
||||
"b" "This is a multi choice option." 'third
|
||||
(list #(first "First Option" "Help for first option.")
|
||||
#(second "Second Option" "Help for second option.")
|
||||
#(third "Third Option" "Help for third option.")
|
||||
@ -54,8 +54,8 @@
|
||||
;; other key is 'a'.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-string-option
|
||||
"Page Two" "String Option"
|
||||
"b" "This is a string option" "Hello, World"))
|
||||
"Hello, World!" "String Option"
|
||||
"c" "This is a string option" "Hello, World"))
|
||||
|
||||
;; This is a date/time option. The user can pick a date and,
|
||||
;; possibly, a time. Times are stored as a pair
|
||||
@ -65,8 +65,8 @@
|
||||
;; time.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-date-option
|
||||
"Time and Date" "Just a Date Option"
|
||||
"a" "This is a date option"
|
||||
"Hello, World!" "Just a Date Option"
|
||||
"d" "This is a date option"
|
||||
(lambda () (cons (current-time) 0))
|
||||
#f))
|
||||
|
||||
@ -74,11 +74,26 @@
|
||||
;; the time.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-date-option
|
||||
"Time and Date" "Time and Date Option"
|
||||
"b" "This is a date option with time"
|
||||
"Hello, World!" "Time and Date Option"
|
||||
"e" "This is a date option with time"
|
||||
(lambda () (cons (current-time) 0))
|
||||
#t))
|
||||
|
||||
;; This is a color option, defined by rgba values. A color value
|
||||
;; is a list where the elements are the red, green, blue, and
|
||||
;; alpha channel values respectively. The penultimate argument
|
||||
;; (255) is the allowed range of rgba values. The final argument
|
||||
;; (#f) indicates the alpha value should be ignored. You can get
|
||||
;; a color string from a color option with gnc:color-option->html,
|
||||
;; which will scale the values appropriately according the range.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-color-option
|
||||
"Hello, World!" "Background Color"
|
||||
"f" "This is a color option"
|
||||
(list #x99 #xcc #xff 0)
|
||||
255
|
||||
#f))
|
||||
|
||||
;; This is an account list option. The user can select one
|
||||
;; or (possibly) more accounts from the list of accounts
|
||||
;; in the current file. Values are scheme handles to actual
|
||||
@ -96,11 +111,20 @@
|
||||
;; selected account in the main window, if any.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-account-list-option
|
||||
"Page One" "An account list option"
|
||||
"b" "This is an account list option"
|
||||
"Hello, World!" "An account list option"
|
||||
"g" "This is an account list option"
|
||||
(lambda () (gnc:get-current-accounts))
|
||||
#f #t))
|
||||
|
||||
;; This option is for testing. When true, the report generates
|
||||
;; an exception.
|
||||
(gnc:register-dummy-option
|
||||
(gnc:make-simple-boolean-option
|
||||
"Testing" "Crash the report"
|
||||
"a" (string-append "This is for testing. "
|
||||
"Your reports probably shouldn't have an "
|
||||
"option like this.") #f))
|
||||
|
||||
gnc:*dummy-options*)
|
||||
|
||||
;; This is a helper function to generate an html list of account names
|
||||
@ -138,33 +162,43 @@
|
||||
;; options in the set of options given to the function. This set will
|
||||
;; be generated by the options generator above.
|
||||
;; Use (gnc:lookup-option options section name) to get the option.
|
||||
(let ((boolop (gnc:lookup-option options "Page One" "Boolean Option"))
|
||||
(let ((boolop (gnc:lookup-option options
|
||||
"Hello, World!" "Boolean Option"))
|
||||
(multop (gnc:lookup-option options
|
||||
"Page Two" "Multi Choice Option"))
|
||||
(strop (gnc:lookup-option options "Page Two" "String Option"))
|
||||
"Hello, World!" "Multi Choice Option"))
|
||||
(strop (gnc:lookup-option options
|
||||
"Hello, World!" "String Option"))
|
||||
(dateop (gnc:lookup-option options
|
||||
"Time and Date" "Just a Date Option"))
|
||||
"Hello, World!" "Just a Date Option"))
|
||||
(dateop2 (gnc:lookup-option options
|
||||
"Time and Date" "Time and Date Option"))
|
||||
"Hello, World!" "Time and Date Option"))
|
||||
(colorop (gnc:lookup-option options
|
||||
"Hello, World!" "Background Color"))
|
||||
(account-list-op (gnc:lookup-option options
|
||||
"Page One"
|
||||
"An account list option")))
|
||||
(let ((time-string (strftime "%c" (localtime (current-time))))
|
||||
"Hello, World!"
|
||||
"An account list option"))
|
||||
(crash-op (gnc:lookup-option options "Testing" "Crash the report")))
|
||||
|
||||
(let ((time-string (strftime "%X" (localtime (current-time))))
|
||||
(date-string (strftime "%x" (localtime (car (gnc:option-value
|
||||
dateop)))))
|
||||
(date-string2 (strftime "%c"
|
||||
(date-string2 (strftime "%x %X"
|
||||
(localtime (car (gnc:option-value
|
||||
dateop2))))))
|
||||
|
||||
;; Crash if asked to.
|
||||
(if (gnc:option-value crash-op)
|
||||
(string-length #f)) ;; this will crash
|
||||
|
||||
;; Here's where we generate the html. A real report would need
|
||||
;; much more code and involve many more utility functions. See
|
||||
;; the other reports for details. Note that you can used nested
|
||||
;; lists here, as well as arbitrary functions.
|
||||
(list
|
||||
"<html>"
|
||||
"<body>"
|
||||
"<body bgcolor=" (gnc:color-option->html colorop) ">"
|
||||
|
||||
"<h2>Hello, World Report</h2>"
|
||||
"<h2>Hello, World</h2>"
|
||||
|
||||
(list "<p>"
|
||||
"This is a sample GnuCash report. "
|
||||
|
@ -3,8 +3,6 @@
|
||||
;; Report on all transactions in an account
|
||||
;; Robert Merkel (rgmerk@mira.net)
|
||||
|
||||
(use-modules (ice-9 slib))
|
||||
(require 'printf)
|
||||
(require 'sort)
|
||||
|
||||
;hack alert - is this line necessary?
|
||||
@ -215,7 +213,7 @@
|
||||
|
||||
(define (gnc:tr-report-get-first-acc-name split-scm)
|
||||
(let ((other-splits (gnc:tr-report-get-other-splits split-scm)))
|
||||
(cond ((= (length other-splits) 0) "")
|
||||
(cond ((= (length other-splits) 0) "-")
|
||||
(else (caar other-splits)))))
|
||||
|
||||
;;; something like
|
||||
|
1212
src/scm/slib-backup.scm
Normal file
1212
src/scm/slib-backup.scm
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,9 @@
|
||||
;; None of these loads will be affected by any command line arguments
|
||||
;; since arguments aren't parsed until gnc:main is executed.
|
||||
|
||||
(if gnc:*load-slib-backup*
|
||||
(gnc:load "slib-backup.scm"))
|
||||
|
||||
(gnc:load "macros.scm")
|
||||
(gnc:load "config-var.scm")
|
||||
(gnc:load "utilities.scm")
|
||||
|
@ -38,6 +38,8 @@
|
||||
#define HH_ADJBWIN "xacc-adjbwin.html"
|
||||
#define HH_MAIN "xacc-main.html"
|
||||
#define HH_GPL "xacc-gpl.html"
|
||||
#define HH_GLOBPREFS "xacc-globalprefs.html"
|
||||
#define HH_ACCEDIT "xacc-accountedit.html"
|
||||
|
||||
/** STRUCTS *********************************************************/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user