more double-entry fixes and extensions

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 1997-11-01 02:20:15 +00:00
parent 2dad05d314
commit 2f0e6918aa
12 changed files with 1348 additions and 801 deletions

View File

@ -41,7 +41,9 @@ RANLIB = ranlib
# USEDEBUG - causes debugging info to be displayed
CFLAGS = $(LFLAGS) -I../include -I../libhtmlw -I/usr/X11/include \
-I/usr/local/include -DMOTIF1_2 \
-DDEBUGMEMORY -DUSEDEBUG
# -DDEBUGMEMORY -DUSEDEBUG
# -DUSEQUICKFILL # -DUSE_NO_COLOR -DDEBUGMEMORY -DUSEDEBUG
LFLAGS = -g -L/usr/local/lib -L/usr/X11/lib
LIBS = -lXm -lXmu -lXbae -lXt -lXext -lX11 -lSM -lICE -lXpm

52
README
View File

@ -39,18 +39,48 @@ sorry, no "make install" yet.
Status:
-------
As of version 0.9c, Mutual fund and Stock Portfolio handling
is implemented, but is very much in alpha state: many features
are missing, and others are broken. In particular, mutual funds
cannot be saved to disk. Also, transfers to bank accounts are
not properly supported. Also, tabbing between fields for
mutual funds does not work correctly.
As of version 0.9f:
---------------
Mutual fund and Stock Portfolio handling
is implemented, but is in alpha state: many features are
missing, and others are broken. Transfers between funds and
bank accounts are not properly supported. Also, tabbing between
fields for mutual funds does not work correctly. One planned
addition is an indication of the type of transaction (Buy,
Cap Gain, Dividend Reinvest, etc.) But it is not clear when
this will be added.
An alpha version of import from quicken files is also present,
--------
An alpha version of import from Quicken files is also present,
but it is very broken, and many/most quicken formats are not
supported.
supported. It is not currently enabled in the code ... adventrous
coders are encouraged to hack on this ...
An alpha-level double-entry system has been created. Its use
is not currently forced. It is used only during transfers
between accounts. It is not saved to file, or read from file.
------------
An beta-level double-entry system has been created.
"Double-entry" is a form of accounting where all transactions
show up in two accounts (for example, a transfer from
a credit card(Diners Club) to a cash account(Entertainment Expense)
will show up in both accounts. Modifying/deleting a transaction
in one account window automatically modifies/deletes it in the
other too.
The system does not force the use of double-entry: in fact,
double entries are made ONLY when the "transfer" menu item is
used.
A future extension to force the use of double-entry for an account
is planned, as well as the ability to make transfers directly
from the register(ledger) window. However, this function will
be tricky, since it requires hacks on the Xbae widget used to
display the register.
Double-entries should be correctly saved-to-file & restored
from file.
-------------
The "reports" menu item is unimplemented and will result in a core dump.
-------------
That's all folks!

View File

@ -44,6 +44,7 @@
typedef struct _accwindow {
String notes; /* The text from the "Notes" window */
/* The account type buttons: */
Widget dialog;
Widget bank;
Widget cash;
Widget asset;
@ -116,6 +117,7 @@ accWindow( Widget parent )
XtAddCallback( dialog, XmNdestroyCallback,
closeAccWindow, (XtPointer)accData );
accData->dialog = dialog;
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog,
@ -320,8 +322,10 @@ accWindow( Widget parent )
XtAddCallback( widget, XmNactivateCallback,
createCB, (XtPointer)accData );
/* We need to do something to clean up memory too! */
/* this is done at endo fo dialog.
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
*/
XtManageChild(buttonform);
@ -585,13 +589,38 @@ createCB( Widget mw, XtPointer cd, XtPointer cb )
Transaction *trans;
Account *acc;
AccWindow *accData = (AccWindow *)cd;
Boolean set = False;
String name = XmTextGetString(accData->name);
String desc = XmTextGetString(accData->desc);
{
/* since portfolio & mutual not fully implemented, provide warning */
int warn = 0;
XtVaGetValues( accData->portfolio, XmNset, &set, NULL );
if(set) warn = 1;
XtVaGetValues( accData->mutual, XmNset, &set, NULL );
if(set) warn = 1;
if (warn) {
int do_it_anyway;
do_it_anyway = verifyBox (toplevel,
"Warning: Portfolio and Mutual Fund \n\
Account types are not fully implemented. \n\
You can play with the interface here, \n\
but doing so may damage your data. \n\
You have been warned! \n\
Do you want to continue anyway?\n");
if (!do_it_anyway) return;
}
}
/* The account has to have a name! */
if( strcmp( name, "" ) == 0 )
if( strcmp( name, "" ) == 0 ) {
errorBox (toplevel, "The account must be given a name! \n");
return;
}
acc = mallocAccount();
acc->flags = 0;
@ -600,37 +629,34 @@ createCB( Widget mw, XtPointer cd, XtPointer cb )
acc->notes = accData->notes;
/* figure out account type */
{
Boolean set = False;
XtVaGetValues( accData->bank, XmNset, &set, NULL );
if(set)
acc->type = BANK;
XtVaGetValues( accData->cash, XmNset, &set, NULL );
if(set)
acc->type = CASH;
XtVaGetValues( accData->asset, XmNset, &set, NULL );
if(set)
acc->type = ASSET;
XtVaGetValues( accData->credit, XmNset, &set, NULL );
if(set)
acc->type = CREDIT;
XtVaGetValues( accData->liability, XmNset, &set, NULL );
if(set)
acc->type = LIABILITY;
XtVaGetValues( accData->portfolio, XmNset, &set, NULL );
if(set)
acc->type = PORTFOLIO;
XtVaGetValues( accData->mutual, XmNset, &set, NULL );
if(set)
acc->type = MUTUAL;
}
XtVaGetValues( accData->bank, XmNset, &set, NULL );
if(set)
acc->type = BANK;
XtVaGetValues( accData->cash, XmNset, &set, NULL );
if(set)
acc->type = CASH;
XtVaGetValues( accData->asset, XmNset, &set, NULL );
if(set)
acc->type = ASSET;
XtVaGetValues( accData->credit, XmNset, &set, NULL );
if(set)
acc->type = CREDIT;
XtVaGetValues( accData->liability, XmNset, &set, NULL );
if(set)
acc->type = LIABILITY;
XtVaGetValues( accData->portfolio, XmNset, &set, NULL );
if(set)
acc->type = PORTFOLIO;
XtVaGetValues( accData->mutual, XmNset, &set, NULL );
if(set)
acc->type = MUTUAL;
/* Add an opening balance transaction (as the first transaction) */
trans = mallocTransaction();
@ -650,6 +676,9 @@ createCB( Widget mw, XtPointer cd, XtPointer cb )
refreshMainWindow();
/* open up the account window for the user */
regWindow( toplevel, acc );
/* if we got to here, tear down the dialog window */
XtDestroyWidget (accData->dialog);
}
/********************************************************************\

View File

@ -30,6 +30,7 @@
#include "date.h"
extern Data *data;
int next_free_unique_account_id = 0;
/********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I *
@ -45,6 +46,13 @@ mallocAccount( void )
{
Account *acc = (Account *)_malloc(sizeof(Account));
acc->id = next_free_unique_account_id;
next_free_unique_account_id ++;
acc->data = NULL;
acc->balance = 0.0;
acc->cleared_balance = 0.0;
acc->flags = 0;
acc->type = 0;
@ -104,13 +112,10 @@ freeAccount( Account *acc )
Transaction *
getTransaction( Account *acc, int num )
{
if( acc != NULL )
{
if( (0 <= num) && (num < acc->numTrans) )
return acc->transaction[num];
else
return NULL;
}
if( NULL == acc ) return NULL;
if( (num >= 0) && (num < acc->numTrans) )
return acc->transaction[num];
else
return NULL;
}
@ -194,7 +199,7 @@ insertTransaction( Account *acc, Transaction *trans )
/* If this appears to be a new transaction, then default
* it to being a credit. If this transaction is already
* in another account, assume this is the other half.
* This algoriothm is not robust against internal programming
* This algorithm is not robust against internal programming
* errors ... various bizarre situations can sneak by without
* warning ... however, this will do for now.
*/
@ -272,6 +277,8 @@ insertTransaction( Account *acc, Transaction *trans )
double xaccGetAmount (Account *acc, Transaction *trans)
{
double themount; /* amount */
if (NULL == trans) return 0.0;
if (NULL == acc) return 0.0;
/* for a double-entry, determine if this is a credit or a debit */
if ( trans->credit == ((struct _account *) acc) ) {
@ -305,4 +312,193 @@ void xaccSetAmount (Account *acc, Transaction *trans, double themount)
}
}
/* -------------------- end of file --------------- */
/********************************************************************\
\********************************************************************/
double xaccGetBalance (Account *acc, Transaction *trans)
{
double themount; /* amount */
/* for a double-entry, determine if this is a credit or a debit */
if ( trans->credit == ((struct _account *) acc) ) {
themount = trans->credit_balance;
} else
if ( trans->debit == ((struct _account *) acc) ) {
themount = trans->debit_balance;
} else {
printf ("Internal Error: xaccGetBalance: missing double entry \n");
printf ("this error should not occur. Please report the problem. \n");
themount = 0.0; /* punt */
}
return themount;
}
/********************************************************************\
\********************************************************************/
double xaccGetClearedBalance (Account *acc, Transaction *trans)
{
double themount; /* amount */
/* for a double-entry, determine if this is a credit or a debit */
if ( trans->credit == ((struct _account *) acc) ) {
themount = trans->credit_cleared_balance;
} else
if ( trans->debit == ((struct _account *) acc) ) {
themount = trans->debit_cleared_balance;
} else {
printf ("Internal Error: xaccGetClearedBalance: missing double entry \n");
printf ("this error should not occur. Please report the problem. \n");
themount = 0.0; /* punt */
}
return themount;
}
/********************************************************************\
\********************************************************************/
double xaccGetShareBalance (Account *acc, Transaction *trans)
{
double themount; /* amount */
/* for a double-entry, determine if this is a credit or a debit */
if ( trans->credit == ((struct _account *) acc) ) {
themount = trans->credit_share_balance;
} else
if ( trans->debit == ((struct _account *) acc) ) {
themount = trans->debit_share_balance;
} else {
printf ("Internal Error: xaccGetShareBalance: missing double entry \n");
printf ("this error should not occur. Please report the problem. \n");
themount = 0.0; /* punt */
}
return themount;
}
/********************************************************************\
* xaccRecomputeBalance *
* recomputes the partial balances and the current balance for *
* this account. *
The current balance is always the current share balance times the
current share price. The share price for bank accounts is always 1.0,
so, for bank acccounts, the current balance is always equal to the current
share balance.
* *
* Args: account -- the account for which to recompute balances *
* Return: void *
\********************************************************************/
void
xaccRecomputeBalance( Account * acc )
{
int i;
double dbalance = 0.0;
double dcleared_balance = 0.0;
Transaction *trans;
if( NULL == acc ) return;
for( i=0; (trans=getTransaction(acc,i)) != NULL; i++ ) {
dbalance += xaccGetAmount (acc, trans);
if( trans->reconciled != NREC ) {
dcleared_balance += xaccGetAmount (acc, trans);
}
if (acc == (Account *) trans->credit) {
trans -> credit_share_balance = dbalance;
trans -> credit_share_cleared_balance = dcleared_balance;
trans -> credit_balance = trans->share_price * dbalance;
trans -> credit_cleared_balance = trans->share_price * dcleared_balance;
}
if (acc == (Account *) trans->debit) {
trans -> debit_share_balance = dbalance;
trans -> debit_share_cleared_balance = dcleared_balance;
trans -> debit_balance = trans->share_price * dbalance;
trans -> debit_cleared_balance = trans->share_price * dcleared_balance;
}
}
acc -> balance = dbalance;
acc -> cleared_balance = dcleared_balance;
return;
}
/********************************************************************\
* xaccCheckDateOrder *
* check this transaction to see if the date is in correct order *
* If it is not, reorder the transactions ... *
* *
* Args: acc -- the account to check *
* trans -- the transaction to check *
*
* Return: int -- non-zero if out of order *
\********************************************************************/
int
xaccCheckDateOrder (Account * acc, Transaction *trans )
{
int outOfOrder = 0;
Transaction *prevTrans;
Transaction *nextTrans;
int position;
if (NULL == acc) return 0;
position = getNumOfTransaction (acc, trans);
/* if transaction not present in the account, its because
* it hasn't been inserted yet. Insert it now. */
if (-1 == position) {
insertTransaction( acc, trans );
return 1;
}
prevTrans = getTransaction( acc, position-1 );
nextTrans = getTransaction( acc, position+1 );
/* figure out if the transactions are out of order */
if (NULL != prevTrans) {
if( datecmp(&(prevTrans->date),&(trans->date))>0 ) outOfOrder = True;
}
if (NULL != nextTrans) {
if( datecmp(&(trans->date),&(nextTrans->date))>0 ) outOfOrder = True;
}
/* take care of re-ordering, if necessary */
if( outOfOrder ) {
removeTransaction( acc, position );
insertTransaction( acc, trans );
return 1;
}
return 0;
}
/********************************************************************\
* xaccCheckDateOrderDE *
* check this transaction to see if the date is in correct order *
* If it is not, reorder the transactions ... *
* This routine perfroms the check for both of the double-entry *
* transaction entries ... *
* *
* Args: trans -- the transaction to check *
* Return: int -- non-zero if out of order *
\********************************************************************/
int
xaccCheckDateOrderDE (Transaction *trans )
{
Account * acc;
int outOfOrder = 0;
if (NULL == trans) return 0;
acc = (Account *) (trans->credit);
outOfOrder += xaccCheckDateOrder (acc, trans);
acc = (Account *) (trans->debit);
outOfOrder += xaccCheckDateOrder (acc, trans);
if (outOfOrder) return 1;
return 0;
}
/*************************** end of file **************************** */

View File

@ -1,6 +1,7 @@
/********************************************************************\
* Data.c -- the main data structure of the program *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -83,6 +84,30 @@ getAccount( Data *data, int num )
return NULL;
}
/********************************************************************\
* Fetch an account, given only it's ID number *
\********************************************************************/
Account *
xaccGetPeerAccountFromID ( Account *acc, int acc_id )
{
Data * data;
Account *peer_acc;
int i;
if (NULL == acc) return NULL;
if (-1 >= acc_id) return NULL;
data = (Data *) acc->data;
for (i=0; i<data->numAcc; i++) {
peer_acc = data->account[i];
if (acc_id == peer_acc->id) return peer_acc;
}
return NULL;
}
/********************************************************************\
\********************************************************************/
Account *
@ -124,26 +149,30 @@ int
insertAccount( Data *data, Account *acc )
{
int i=-1;
Account **oldAcc;
if( data != NULL )
{
Account **oldAcc = data->account;
if (NULL == data) return -1;
if (NULL == acc) return -1;
/* set back-pointer to the accounts parent */
acc->data = (struct _data *) data;
oldAcc = data->account;
data->saved = False;
data->numAcc++;
data->account = (Account **)_malloc((data->numAcc)*sizeof(Account *));
for( i=0; i<(data->numAcc-1); i++ )
data->account[i] = oldAcc[i];
data->account[i] = acc;
_free(oldAcc);
}
data->saved = False;
data->numAcc++;
data->account = (Account **)_malloc((data->numAcc)*sizeof(Account *));
for( i=0; i<(data->numAcc-1); i++ )
data->account[i] = oldAcc[i];
data->account[i] = acc;
_free(oldAcc);
return i;
}
/****************** END OF FILE *************************************/

View File

@ -2,6 +2,7 @@
* FileIO.c -- read from and writing to a datafile for xacc *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -27,12 +28,17 @@
* position in the file, and so the order which these *
* functions are called in important *
* *
* Version 2 of the file format supports reading and writing of *
* double-entry transactions. *
* *
* *
* the format of the data in the file: *
* file ::== token numAccounts (Account)^numAccounts *
* Account ::== flags type accountName description notes *
* Account ::== num flags type accountName description notes *
* numTran (Transaction)^numTrans *
* Transaction ::== num date description memo catagory reconciled *
* amount *
* amount share_price *
* credit_account debit_account *
* token ::== int [the version of file format == VERSION] *
* numTrans ::== int *
* numAccounts ::== int *
@ -41,13 +47,17 @@
* accountName ::== String *
* description ::== String *
* notes ::== String *
* *
* num ::== String *
* date ::== Date *
* description ::== String *
* memo ::== String *
* catagory ::== int *
* reconciled ::== char *
* amount ::== int *
* amount ::== double *
* share_price ::== double *
* credit_account ::= int *
* debit_account ::= int *
* String ::== size (char)^size *
* size ::== int *
* Date ::== year month day *
@ -66,14 +76,14 @@
#define PERMS 0666
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define RFLAGS O_RDONLY
#define VERSION 1
#define VERSION 2
/** GLOBALS *********************************************************/
extern Widget toplevel;
/** PROTOTYPES ******************************************************/
Account *readAccount( int fd, int token );
Transaction *readTransaction( int fd, int token );
int readAccount( int fd, Account *, int token );
Transaction *readTransaction( int fd, Account *, int token );
char *readString( int fd, int token );
Date *readDate( int fd, int token );
@ -184,19 +194,26 @@ readData( char *datafile )
}
XACC_FLIP_INT (numAcc);
/* malloc the accounts, in preparation for reading.
* Mmalloc all of them; they will be needed for up front
* for inserting the double-entry transactions */
for( i=0; i<numAcc; i++ )
{
Account *acc = mallocAccount();
insertAccount( data, acc );
}
/* read in the accounts */
for( i=0; i<numAcc; i++ )
{
Account *acc;
acc = readAccount( fd, token );
if( acc == NULL )
Account *acc = getAccount (data, i);
err = readAccount( fd, acc, token );
if( -1 == err )
{
close(fd);
printf(" numAcc = %d\n i = %d\n",numAcc,i);
printf(" numAcc = %d, i = %d\n",numAcc,i);
return data;
}
else
insertAccount( data, acc );
}
close(fd);
@ -208,57 +225,78 @@ readData( char *datafile )
* reads in the data for an account from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* acc - the account structure to be filled in *
* token - the datafile version *
* Return: the account structure *
* Return: error value, 0 if OK, else -1 *
\********************************************************************/
Account *
readAccount( int fd, int token )
int
readAccount( int fd, Account *acc, int token )
{
int err=0;
int i;
int numTrans;
Account *acc = mallocAccount();
int numTrans, nacc;
ENTER ("readAccount");
/* version 1 does not store the account number */
if (1 < token) {
err = read( fd, &nacc, sizeof(int) );
if( err != sizeof(int) )
{
freeAccount(acc);
return -1;
}
XACC_FLIP_INT (nacc);
/* normalize the account numbers -- positive-definite.
* That is, the unique id must never decrease,
* nor must it overalp any existing account id */
acc->id = nacc;
if (next_free_unique_account_id <= nacc) {
next_free_unique_account_id = nacc+1;
}
}
err = read( fd, &(acc->flags), sizeof(char) );
if( err != sizeof(char) )
{
freeAccount(acc);
return NULL;
return -1;
}
err = read( fd, &(acc->type), sizeof(char) );
if( err != sizeof(char) )
{
freeAccount(acc);
return NULL;
return -1;
}
acc->accountName = readString( fd, token );
if( acc->accountName == NULL )
{
freeAccount(acc);
return NULL;
return -1;
}
acc->description = readString( fd, token );
if( acc->description == NULL )
{
freeAccount(acc);
return NULL;
return -1;
}
acc->notes = readString( fd, token );
if( acc->notes == NULL )
{
freeAccount(acc);
return NULL;
return -1;
}
err = read( fd, &numTrans, sizeof(int) );
if( err != sizeof(int) )
{
freeAccount(acc);
return NULL;
return -1;
}
XACC_FLIP_INT (numTrans);
@ -266,17 +304,16 @@ readAccount( int fd, int token )
for( i=0; i<numTrans; i++ )
{
Transaction *trans;
trans = readTransaction( fd, token );
trans = readTransaction( fd, acc, token );
if( trans == NULL )
{
printf(" numTrans = %d\n i = %d\n",numTrans,i);
return acc;
printf("Error: readAccount: Premature termination: \n");
printf (" numTrans = %d i = %d\n",numTrans,i);
return 0;
}
else
insertTransaction( acc, trans );
}
return acc;
return 0;
}
/********************************************************************\
@ -288,16 +325,19 @@ readAccount( int fd, int token )
* Return: the transaction structure *
\********************************************************************/
Transaction *
readTransaction( int fd, int token )
readTransaction( int fd, Account *acc, int token )
{
int err=0;
int acc_id;
Date *date;
Transaction *trans = mallocTransaction();
int amount;
ENTER ("readTransaction");
trans->num = readString( fd, token );
if( trans->num == NULL )
{
DEBUG ("Error: Premature end of Transaction at num");
_free(trans);
return NULL;
}
@ -305,6 +345,7 @@ readTransaction( int fd, int token )
date = readDate( fd, token );
if( date == NULL )
{
DEBUG ("Error: Premature end of Transaction at date");
XtFree(trans->num);
_free(trans);
return NULL;
@ -315,6 +356,7 @@ readTransaction( int fd, int token )
trans->description = readString( fd, token );
if( trans->description == NULL )
{
DEBUG ("Error: Premature end of Transaction at description");
XtFree(trans->num);
_free(trans);
return NULL;
@ -323,6 +365,7 @@ readTransaction( int fd, int token )
trans->memo = readString( fd, token );
if( trans->memo == NULL )
{
DEBUG ("Error: Premature end of Transaction at memo");
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
@ -332,6 +375,7 @@ readTransaction( int fd, int token )
err = read( fd, &(trans->catagory), sizeof(int) );
if( err != sizeof(int) )
{
DEBUG ("Error: Premature end of Transaction at category");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
@ -343,6 +387,7 @@ readTransaction( int fd, int token )
err = read( fd, &(trans->reconciled), sizeof(char) );
if( err != sizeof(char) )
{
DEBUG ("Error: Premature end of Transaction at reconciled");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
@ -353,7 +398,8 @@ readTransaction( int fd, int token )
/* What used to be reconciled, is now cleared... transactions
* aren't reconciled until you get your bank statement, and
* use the reconcile window to mark the transaction reconciled */
if( token == 0 )
/* hack alert -- ?????????? I don't get it ???????????? */
if( 0 <= token )
if( trans->reconciled == YREC )
trans->reconciled = CREC;
@ -364,17 +410,99 @@ readTransaction( int fd, int token )
if( (trans->reconciled != YREC) && (trans->reconciled != CREC) )
trans->reconciled = NREC;
err = read( fd, &amount, sizeof(int) );
if( err != sizeof(int) )
{
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
XACC_FLIP_INT (amount);
trans->damount = 0.01 * ((double) amount); /* file stores pennies */
if (1 == token) {
int amount;
/* version 1 files stored the amount as an integer,
* with the amount recorded as pennies */
err = read( fd, &amount, sizeof(int) );
if( err != sizeof(int) )
{
DEBUG ("Error: Premature end of Transaction at V1 amount");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
XACC_FLIP_INT (amount);
trans->damount = 0.01 * ((double) amount); /* file stores pennies */
} else {
double damount;
/* first, read number of shares ... */
err = read( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
{
DEBUG ("Error: Premature end of Transaction at amount");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
trans->damount = damount;
/* ... next read the share price ... */
err = read( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
{
DEBUG ("Error: Premature end of Transaction at share_price");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
trans->share_price = damount;
}
DEBUGCMD(printf ("Info: readTransaction(): amount %f \n", trans->damount));
/* read the account numbers for double-entry */
/* these are first used in version 2 of the file format */
if (1 < token) {
Account *peer_acc;
/* first, read the credit account number */
err = read( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
{
DEBUG ("Error: Premature end of Transaction at credit");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
return NULL;
}
XACC_FLIP_INT (acc_id);
DEBUGCMD (printf ("Info: readTransaction(): credit %d\n", acc_id));
peer_acc = xaccGetPeerAccountFromID (acc, acc_id);
trans -> credit = (struct _account *) peer_acc;
/* insert the transaction into both the debit and
* the credit accounts; first the credit ... */
if (peer_acc) insertTransaction( peer_acc, trans );
/* next read the debit account number */
err = read( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
{
DEBUG ("Error: Premature end of Transaction at debit");
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
return NULL;
}
XACC_FLIP_INT (acc_id);
DEBUGCMD (printf ("Info: readTransaction(): debit %d\n", acc_id));
peer_acc = xaccGetPeerAccountFromID (acc, acc_id);
trans -> debit = (struct _account *) peer_acc;
/* insert the transaction into both the debit and
* the credit accounts; next, the debit ... */
if (peer_acc) insertTransaction( peer_acc, trans );
} else {
/* version 1 files did not do double-entry */
insertTransaction( acc, trans );
}
return trans;
}
@ -403,7 +531,7 @@ readString( int fd, int token )
err = read( fd, str, size );
if( err != size )
{
printf( " size = %d\n err = %d\n str = %s\n", size, err, str );
printf( "Error: readString: size = %d err = %d str = %s\n", size, err, str );
_free(str);
return NULL;
}
@ -471,6 +599,26 @@ writeData( char *datafile, Data *data )
int token = VERSION; /* The file format version */
int fd;
if (NULL == data) return -1;
/* first, zero out the write flag on all of the
* transactions */
numAcc = data ->numAcc;
for( i=0; i<numAcc; i++ ) {
int n=0;
Account *acc;
Transaction * trans;
acc = getAccount (data,i) ;
trans = getTransaction (acc, n);
n++;
while (trans) {
trans->write_flag = 0;
trans = getTransaction (acc, n);
n++;
}
}
/* now, open the file and start writing */
fd = open( datafile, WFLAGS, PERMS );
if( fd == -1 )
{
@ -493,7 +641,7 @@ writeData( char *datafile, Data *data )
if( err != sizeof(int) )
return -1;
for( i=0; i<numAcc; i++ )
for( i=0; i<data->numAcc; i++ )
{
err = writeAccount( fd, getAccount(data,i) );
if( err == -1 )
@ -518,7 +666,15 @@ writeAccount( int fd, Account *acc )
Transaction *trans;
int err=0;
int i,numTrans, ntrans;
int acc_id;
acc_id = acc->id;
DEBUGCMD (printf ("Info: writeAccount: writing acct id %d %x \n", acc_id, acc));
XACC_FLIP_INT (acc_id);
err = write( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, &(acc->flags), sizeof(char) );
if( err != sizeof(char) )
return -1;
@ -539,25 +695,32 @@ writeAccount( int fd, Account *acc )
if( err == -1 )
return err;
/* figure out numTrans */
for( numTrans = 0; getTransaction(acc,numTrans) != NULL; numTrans++ )
{}
/* figure out numTrans -- it will be less than the total
* number of transactions in this account, because some
* of the double entry transactions will already have been
* written. */
numTrans = 0;
i = 0;
trans = getTransaction (acc, i);
while (trans) {
i++;
if (0 == trans->write_flag) numTrans ++;
trans = getTransaction (acc, i);
}
ntrans = numTrans;
XACC_FLIP_INT (ntrans);
err = write( fd, &ntrans, sizeof(int) );
if( err != sizeof(int) )
return -1;
for( i=0; i<numTrans; i++ )
{
for( i=0; i<numTrans; i++ ) {
err = writeTransaction( fd, acc, getTransaction(acc,i) );
if( err == -1 )
return err;
}
if( err == -1 ) return err;
}
return err;
}
}
/********************************************************************\
* writeTransaction *
@ -572,7 +735,15 @@ int
writeTransaction( int fd, Account * acc, Transaction *trans )
{
int err=0;
int tmp;
int tmp, acc_id;
double damount;
Account *xfer_acc;
ENTER ("writeTransaction");
/* if we've already written this transaction, don't write it again */
/* that is, prevent double-entry transactions from being written twice */
if (trans->write_flag) return 4;
trans->write_flag = 1;
err = writeString( fd, trans->num );
if( err == -1 )
@ -600,9 +771,33 @@ writeTransaction( int fd, Account * acc, Transaction *trans )
if( err != sizeof(char) )
return -1;
tmp = (int) (100.0 * xaccGetAmount (acc, trans)); /* file stores pennies */
XACC_FLIP_INT (tmp);
err = write( fd, &tmp, sizeof(int) );
damount = trans->damount;
DEBUGCMD (printf ("Info: writeTransaction: amount=%f \n", damount));
err = write( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
return -1;
damount = trans->share_price;
err = write( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
return -1;
/* write the double-entry values */
xfer_acc = (Account *) (trans->credit);
acc_id = -1;
if (xfer_acc) acc_id = xfer_acc -> id;
DEBUGCMD (printf ("Info: writeTransaction: credit %d \n", acc_id));
XACC_FLIP_INT (acc_id);
err = write( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
return -1;
xfer_acc = (Account *) (trans->debit);
acc_id = -1;
if (xfer_acc) acc_id = xfer_acc -> id;
DEBUGCMD (printf ("Info: writeTransaction: debit %d \n", acc_id));
XACC_FLIP_INT (acc_id);
err = write( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
return -1;
@ -623,6 +818,8 @@ writeString( int fd, char *str )
int err=0;
int size;
int tmp;
if (NULL == str) str = ""; /* protect against null arguments */
for( size=0; str[size] != '\0'; size++ )
{}
@ -676,3 +873,5 @@ writeDate( int fd, Date *date )
return err;
}
/*********************** END OF FILE *********************************/

View File

@ -206,8 +206,14 @@ helpWindow( Widget parent, char *title, char *htmlfile )
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, title,
XmNdeleteResponse, XmDESTROY,
XmNwidth, 500,
XmNheight, 400,
XmNtransient, FALSE, /* allow window to be repositioned */
/*
XmNminWidth, 500,
XmNminHeight, 400,
*/
NULL );
XtAddCallback( dialog, XmNdestroyCallback, closeHelpWin, NULL );

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ void recordCB( Widget mw, XtPointer cd, XtPointer cb );
void deleteCB( Widget mw, XtPointer cd, XtPointer cb );
void cancelCB( Widget mw, XtPointer cd, XtPointer cb );
void regCB( Widget mw, XtPointer cd, XtPointer cb );
void dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs );
void dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs, int do_year );
/** GLOBALS *********************************************************/
@ -277,6 +277,10 @@ regRefresh( RegWindow *regData )
newData[row+1][PRIC_CELL_C] = XtNewString("");
newData[row][SHRS_CELL_C] = XtNewString("");
newData[row+1][SHRS_CELL_C] = XtNewString("");
/*
newData[row][ACTN_CELL_C] = XtNewString("");
newData[row+1][ACTN_CELL_C] = XtNewString("");
*/
break;
default:
fprintf( stderr, "Ineternal Error: Account type: %d is unknown!\n", regData->acc->type);
@ -315,7 +319,7 @@ regRefresh( RegWindow *regData )
/* set the cell data: */
XtVaSetValues( regData->reg, XmNcells, newData, NULL );
regRecalculateBalance(regData);
regRecalculateBalance (regData);
/* and free memory!!! */
/* ??? */
@ -337,31 +341,25 @@ regRecalculateBalance( RegWindow *regData )
int i;
int position = 1;
double dbalance = 0.0;
double share_balance = 0.0;
double dclearedBalance = 0.0;
double share_clearedBalance = 0.0;
double share_balance = 0.0;
char buf[BUFSIZE];
Transaction *trans;
Account *acc;
Widget reg;
if( regData != NULL ) {
reg = regData->reg;
acc = regData->acc;
} else {
reg = NULL;
acc = NULL;
}
if( NULL == regData ) return 0.0;
reg = regData->reg;
acc = regData->acc;
xaccRecomputeBalance (acc);
for( i=0; (trans=getTransaction(regData->acc,i)) != NULL; i++ )
for( i=0; (trans=getTransaction(acc,i)) != NULL; i++ )
{
share_balance += xaccGetAmount (acc, trans);
dbalance = trans -> share_price * share_balance;
if( trans->reconciled != NREC ) {
share_clearedBalance += xaccGetAmount (acc, trans);
dclearedBalance = trans->share_price * share_clearedBalance;
}
dbalance = xaccGetBalance (acc, trans);
dclearedBalance = xaccGetClearedBalance (acc, trans);
share_balance = xaccGetShareBalance (acc, trans);
if( reg != NULL )
{
@ -406,15 +404,12 @@ regRecalculateBalance( RegWindow *regData )
}
}
if( regData != NULL )
if( NULL != regData->balance )
{
if( regData->balance != NULL )
{
sprintf( buf, "$ %.2f \n$ %.2f \0",
dbalance, dclearedBalance );
XmTextSetString( regData->balance, buf );
}
sprintf( buf, "$ %.2f \n$ %.2f \0",
dbalance, dclearedBalance );
XmTextSetString( regData->balance, buf );
}
refreshMainWindow(); /* make sure the balance field in
@ -431,6 +426,19 @@ regRecalculateBalance( RegWindow *regData )
* Return: none *
* Global: data - the data for open datafile *
\********************************************************************/
#define RECALC_BALANCE(sacc) { \
Account * xfer_acc; \
RegWindow * xfer_reg; \
xfer_acc = (Account *) (sacc); \
if (xfer_acc) { \
xfer_reg = (RegWindow *) (xfer_acc->regData); \
if (xfer_reg) { \
regRecalculateBalance (xfer_reg); \
} \
} \
}
void
regSaveTransaction( RegWindow *regData, int position )
{
@ -438,7 +446,6 @@ regSaveTransaction( RegWindow *regData, int position )
* regData->changed is a bitfield that keeps track of things
* that might have changed, so we only have to save the stuff
* that has changed */
Boolean outOfOrder = False;
char buf[BUFSIZE];
int newPosition;
int row = (position * 2) + 1;
@ -524,7 +531,8 @@ regSaveTransaction( RegWindow *regData, int position )
trans->reconciled = (XbaeMatrixGetCell(regData->reg,row,RECN_CELL_C))[0];
/* Remember, we need to recalculate the reconciled balance now! */
regRecalculateBalance(regData);
RECALC_BALANCE ((trans->credit));
RECALC_BALANCE ((trans->debit));
}
if( regData->changed & MOD_AMNT )
@ -561,7 +569,8 @@ regSaveTransaction( RegWindow *regData, int position )
XbaeMatrixSetCell( regData->reg, row, DEP_CELL_C, buf );
}
regRecalculateBalance(regData);
RECALC_BALANCE ((trans->credit));
RECALC_BALANCE ((trans->debit));
}
/* ignore MOD_PRIC if for non-stock accounts */
@ -583,7 +592,8 @@ regSaveTransaction( RegWindow *regData, int position )
XbaeMatrixSetCell( regData->reg, row, PRIC_CELL_C, buf );
/* Remember, we need to recalculate the reconciled balance now! */
regRecalculateBalance(regData);
RECALC_BALANCE ((trans->credit));
RECALC_BALANCE ((trans->debit));
}
/* Before we check the date, and possibly insert the new
@ -602,18 +612,13 @@ regSaveTransaction( RegWindow *regData, int position )
_free(trans);
return;
}
else
{
/* If this is a valid new transaction, add a new
* empty transaction to take its place */
outOfOrder = TRUE;
}
}
if( regData->changed & MOD_DATE )
{
Transaction *prevTrans;
Transaction *nextTrans;
Boolean outOfOrder = False;
prevTrans = getTransaction( acc, position-1 );
nextTrans = getTransaction( acc, position+1 );
@ -623,32 +628,38 @@ regSaveTransaction( RegWindow *regData, int position )
&(trans->date.month),
&(trans->date.day) );
trans->date.year = atoi(XbaeMatrixGetCell(regData->reg,row+1,0));
trans->date.year = atoi(XbaeMatrixGetCell(regData->reg,row+1,DATE_CELL_C));
/* figure out if the transactions are out of order */
if( prevTrans != NULL )
if( datecmp(&(prevTrans->date),&(trans->date))>0 )
outOfOrder = True;
if( nextTrans != NULL )
if( datecmp(&(trans->date),&(nextTrans->date))>0 )
outOfOrder = True;
outOfOrder = xaccCheckDateOrderDE (trans);
/* take care of re-ordering, if necessary */
/* take care of re-ordering implications on the register, if necessary */
if( outOfOrder )
{
/* We need to change lastTrans, because we remove and re-insert
* the transaction... reset lastTrans to zero to prevent it from
* indicating a row that doesn't exist. (That shouldn't happen
* anyways!) */
regData->lastTrans = 0;
/* We don't need to remove if it isn't in the transaction list */
if( !(regData->changed & MOD_NEW) )
removeTransaction( acc, position );
insertTransaction( acc, trans );
regRefresh(regData);
/* REFRESH_REGISTER needs to null out lastTrans, because
* during date reordering we removed and re-inserted
* the transaction... reset lastTrans to zero to prevent it from
* indicating a row that doesn't exist. (That shouldn't happen
* anyways!) */
#define REFRESH_REGISTER(sacc) { \
Account * xfer_acc; \
RegWindow * xfer_reg; \
xfer_acc = (Account *) (sacc); \
if (xfer_acc) { \
xfer_reg = (RegWindow *) (xfer_acc->regData); \
if (xfer_reg) { \
xfer_reg->lastTrans = 0; \
regRefresh (xfer_reg); \
} \
} \
}
/* if the date changed on a double-entry (transfer) transaction,
* then make sure that both register windows are updated .. */
REFRESH_REGISTER ((trans->credit));
REFRESH_REGISTER ((trans->debit));
}
/* Scroll to the last row, if it is a new transaction */
@ -658,17 +669,27 @@ regSaveTransaction( RegWindow *regData, int position )
XbaeMatrixMakeCellVisible( regData->reg, lastRow, DESC_CELL_C );
}
/* recalculate the balances, but only after re-ordering
* cells */
regRecalculateBalance(regData);
/* recalculate the balances, but only after re-ordering cells */
RECALC_BALANCE ((trans->credit));
RECALC_BALANCE ((trans->debit));
}
/* reset the "changed" bitfield */
regData->changed = 0;
/* If the reconcile window is open, update it!!! */
if( acc->recnData != NULL )
recnRefresh( acc->recnData );
#define REFRESH_RECONCILE_WIN(sacc) { \
/* If the reconcile window is open, update it!!! */ \
Account * xfer_acc; \
xfer_acc = (Account *) (sacc); \
if (xfer_acc) { \
if (NULL != xfer_acc->recnData) { \
recnRefresh( xfer_acc->recnData ); \
} \
} \
}
REFRESH_RECONCILE_WIN ((trans->credit));
REFRESH_RECONCILE_WIN ((trans->debit));
return;
}
@ -717,9 +738,9 @@ regWindow( Widget parent, Account *acc )
xmDialogShellWidgetClass, parent,
XmNdeleteResponse, XmDESTROY,
XmNtitle, acc->accountName,
XmNwidth, 495,
XmNheight, 500,
/*
XmNwidth, 395,
XmNheight, 400,
XmNminWidth, 495,
XmNmaxWidth, 495,
XmNminHeight, 500,
@ -839,15 +860,15 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc->columnLocation [DATE_COL_ID] = 0;
acc->columnLocation [NUM_COL_ID] = 1;
acc->columnLocation [ACTN_COL_ID] = 2;
acc->columnLocation [DESC_COL_ID] = 3;
acc->columnLocation [RECN_COL_ID] = 4;
acc->columnLocation [PAY_COL_ID] = 5;
acc->columnLocation [DEP_COL_ID] = 6;
acc->columnLocation [PRIC_COL_ID] = 7;
acc->columnLocation [SHRS_COL_ID] = 8;
acc->columnLocation [BALN_COL_ID] = 9;
acc -> numCols = 10;
/* acc->columnLocation [ACTN_COL_ID] = 2; */
acc->columnLocation [DESC_COL_ID] = 2;
acc->columnLocation [RECN_COL_ID] = 3;
acc->columnLocation [PAY_COL_ID] = 4;
acc->columnLocation [DEP_COL_ID] = 5;
acc->columnLocation [PRIC_COL_ID] = 6;
acc->columnLocation [SHRS_COL_ID] = 7;
acc->columnLocation [BALN_COL_ID] = 8;
acc -> numCols = 9;
break;
default:
fprintf( stderr, "Ineternal Error: Account type: %d is unknown!\n", acc->type);
@ -856,7 +877,7 @@ regWindow( Widget parent, Account *acc )
/* ----------------------------------- */
/* set up column widths */
acc -> colWidths[DATE_CELL_C] = 4; /* the widths of columns */
acc -> colWidths[DATE_CELL_C] = 5; /* the widths of columns */
acc -> colWidths[NUM_CELL_C] = 4; /* the widths of columns */
acc -> colWidths[DESC_CELL_C] = 35; /* the widths of columns */
acc -> colWidths[RECN_CELL_C] = 1; /* the widths of columns */
@ -876,7 +897,7 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc -> colWidths[PRIC_CELL_C] = 8; /* price */
acc -> colWidths[SHRS_CELL_C] = 8; /* share balance */
acc -> colWidths[ACTN_CELL_C] = 6; /* action (category) */
/* acc -> colWidths[ACTN_CELL_C] = 6; /* action (category) */
break;
}
@ -904,7 +925,7 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc -> alignments[PRIC_CELL_C] = XmALIGNMENT_END; /* price */
acc -> alignments[SHRS_CELL_C] = XmALIGNMENT_END; /* share balance */
acc -> alignments[ACTN_CELL_C] = XmALIGNMENT_BEGINNING; /* action */
/* acc -> alignments[ACTN_CELL_C] = XmALIGNMENT_BEGINNING; /* action */
break;
}
@ -932,7 +953,7 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc -> rows[0][PRIC_CELL_C] = "Price";
acc -> rows[0][SHRS_CELL_C] = "Tot Shrs";
acc -> rows[0][ACTN_CELL_C] = "Cat";
/* acc -> rows[0][ACTN_CELL_C] = "Cat"; /* action */
break;
}
@ -976,7 +997,7 @@ regWindow( Widget parent, Account *acc )
XmNfixedRows, 1,
XmNfixedColumns, 0,
XmNrows, 2,
XmNvisibleRows, 20,
XmNvisibleRows, 15,
XmNfill, True,
XmNcolumns, acc -> numCols,
XmNcolumnWidths, acc -> colWidths,
@ -1206,12 +1227,30 @@ recordCB( Widget mw, XtPointer cd, XtPointer cb )
* cb - *
* Return: none *
\********************************************************************/
#define REMOVE_TRANS(sacc,trans) { \
Account *otherAcc = (Account *) (sacc); \
if (otherAcc) { \
RegWindow *otherRegData = otherAcc -> regData; \
int n = getNumOfTransaction (otherAcc, trans); \
\
/* remove the transaction */ \
trans = removeTransaction( otherAcc, n ); \
\
/* remove the rows from the matrix */ \
if (otherRegData) { \
int otherrow = 2*n + 1; \
XbaeMatrixDeleteRows( otherRegData->reg, otherrow, 2 ); \
XbaeMatrixRefresh( otherRegData->reg); \
} \
} \
}
void
deleteCB( Widget mw, XtPointer cd, XtPointer cb )
{
RegWindow *regData = (RegWindow *)cd;
Account *acc = regData->acc;
Account *otherAcc = 0x0;
if( getTransaction(acc,regData->lastTrans) != NULL )
{
@ -1220,37 +1259,17 @@ deleteCB( Widget mw, XtPointer cd, XtPointer cb )
if( verifyBox( toplevel, msg ) )
{
Transaction *trans;
int row = (2*regData->lastTrans) + 1;
/* remove the transaction */
trans = removeTransaction( acc, regData->lastTrans );
trans = getTransaction (acc, regData->lastTrans );
/* remove the rows from the matrix */
XbaeMatrixDeleteRows( regData->reg, row, 2 );
XbaeMatrixRefresh(regData->reg);
/* if this is a double entry transaction,
* remove it from the other account too ...... */
if (trans->credit) otherAcc = (Account *) trans->credit;
if (trans->debit) otherAcc = (Account *) trans->debit;
if (otherAcc) {
RegWindow *otherRegData = otherAcc -> regData;
int otherrow;
int n = getNumOfTransaction (otherAcc, trans);
trans = removeTransaction( otherAcc, n );
/* remove the transaction from both accounts */
REMOVE_TRANS ((trans->credit), trans);
REMOVE_TRANS ((trans->debit), trans);
/* remove the rows from the matrix */
if (otherRegData) {
otherrow = 2*n + 1;
XbaeMatrixDeleteRows( otherRegData->reg, otherrow, 2 );
XbaeMatrixRefresh( otherRegData->reg);
regRecalculateBalance (otherRegData);
}
}
RECALC_BALANCE ((trans->debit));
RECALC_BALANCE ((trans->credit));
/* Delete the transaction */
freeTransaction (trans);
regRecalculateBalance(regData);
}
}
}
@ -1327,7 +1346,7 @@ regCB( Widget mw, XtPointer cd, XtPointer cb )
!IN_RECN_CELL(row,col) && !IN_DEP_CELL(row,col) &&
!((PORTFOLIO == acc->type) && IN_PRIC_CELL(row,col)) &&
!((MUTUAL == acc->type) && IN_PRIC_CELL(row,col)) &&
!IN_MEMO_CELL(row,col) )
!IN_MEMO_CELL(row,col) && !IN_YEAR_CELL(row,col))
{
((XbaeMatrixEnterCellCallbackStruct *)cbs)->doit = FALSE;
((XbaeMatrixEnterCellCallbackStruct *)cbs)->map = FALSE;
@ -1450,7 +1469,11 @@ regCB( Widget mw, XtPointer cd, XtPointer cb )
}
#endif
if( IN_DATE_CELL(row,col) )
dateCellFormat( mw, mvcbs ); /* format according to date
dateCellFormat( mw, mvcbs, 0); /* format according to date
* cell rules */
if( IN_YEAR_CELL(row,col) )
dateCellFormat( mw, mvcbs, 1); /* format according to date
* cell rules */
/* look to see if numeric format is OK. Note that
@ -1491,7 +1514,7 @@ regCB( Widget mw, XtPointer cd, XtPointer cb )
/* if the cell is modified, mark it as modified, so we know to
* save it... (Don't mark reconciled here, because you can't
* actually enter the reconciled cell... mark it in XbaerCellReason */
if( IN_DATE_CELL(row,col) )
if( IN_DATE_CELL(row,col) || IN_YEAR_CELL(row,col) )
regData->changed |= MOD_DATE;
if( IN_NUM_CELL(row,col) )
@ -1613,7 +1636,7 @@ regCB( Widget mw, XtPointer cd, XtPointer cb )
* Return: none *
\********************************************************************/
void
dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs )
dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs, int do_year )
{
/* Date format -- valid characters are numerals, '/', and
* accelerator keys (accelerator keys have doit = False,
@ -1635,15 +1658,24 @@ dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs )
input = (mvcbs->verify->text->ptr)[0];
row = mvcbs->row;
if (do_year) {
row = mvcbs->row - 1;
} else {
row = mvcbs->row;
}
col = mvcbs->column;
date.day = 0;
date.month = 0;
date.year = 0;
sscanf( mvcbs->prev_text,
"%d/%d",&(date.month), &(date.day) );
if (do_year) {
sscanf( XbaeMatrixGetCell(mw,row,col),
"%d/%d",&(date.month), &(date.day) );
}else {
sscanf( mvcbs->prev_text,
"%d/%d",&(date.month), &(date.day) );
}
sscanf( XbaeMatrixGetCell(mw,row+1,col),
"%d", &(date.year) );
@ -1725,19 +1757,20 @@ dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs )
* on the first on, we accept, on the second one
* we skip to the year cell
*/
{
int i,count=0;
DEBUGCMD(printf(" = %s\n",mvcbs->prev_text));
for( i=0; (mvcbs->prev_text)[i] != '\0'; i++ )
if( (mvcbs->prev_text)[i] == '/' )
count++;
if( count >= 1 )
if (0 == do_year)
{
XbaeMatrixEditCell( mw, row+1, col );
XbaeMatrixSelectCell( mw, row+1, col );
int i,count=0;
DEBUGCMD(printf(" = %s\n",mvcbs->prev_text));
for( i=0; (mvcbs->prev_text)[i] != '\0'; i++ )
if( (mvcbs->prev_text)[i] == '/' )
count++;
if( count >= 1 )
{
XbaeMatrixEditCell( mw, row+1, col );
XbaeMatrixSelectCell( mw, row+1, col );
}
}
}
break;
break;
default:
/* only accept the input if it is a number */
mvcbs->verify->doit = isNum(input);
@ -1755,3 +1788,4 @@ dateCellFormat( Widget mw, XbaeMatrixModifyVerifyCallbackStruct *mvcbs )
}
}
/************************** END OF FILE *************************/

View File

@ -52,9 +52,16 @@ initTransaction( Transaction * trans )
trans->damount = 0.0;
trans->share_price = 1.0;
trans->credit_balance = 0.0;
trans->credit_cleared_balance = 0.0;
trans->debit_balance = 0.0;
trans->debit_cleared_balance = 0.0;
trans->date.year = 1900;
trans->date.month = 1;
trans->date.day = 1;
trans->write_flag = 0;
}
/********************************************************************\

View File

@ -38,6 +38,7 @@
#include "main.h"
#include "util.h"
extern Widget toplevel;
typedef struct _menuData
{
@ -47,6 +48,7 @@ typedef struct _menuData
typedef struct _xferwindow
{
Widget dialog;
Widget date;
Widget desc;
Widget amount;
@ -107,12 +109,13 @@ xferWindow( Widget parent )
XtAddCallback( dialog, XmNdestroyCallback,
closeXferWindow, (XtPointer)xferData );
xferData->dialog = dialog;
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog, NULL );
/******************************************************************\
* Text fields.... *
\******************************************************************/
* Text fields.... *
\******************************************************************/
label =
XtVaCreateManagedWidget( "Date",
xmLabelGadgetClass, form,
@ -346,8 +349,10 @@ xferWindow( Widget parent )
XtAddCallback( widget, XmNactivateCallback,
xferCB, (XtPointer)xferData );
/*
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
*/
XtManageChild(buttonform);
@ -422,6 +427,12 @@ xferCB( Widget mw, XtPointer cd, XtPointer cb )
String str;
float val=0.0;
/* silently reject transfers into-out-of the same account */
if (xferData->from == xferData->to) {
errorBox (toplevel, "The \"From\" and \"To\" accounts\n must be different!\n");
return;
}
data->saved = False;
/* a double-entry transfer -- just one record, two accounts */
@ -465,6 +476,9 @@ xferCB( Widget mw, XtPointer cd, XtPointer cb )
recnRefresh(acc->recnData);
refreshMainWindow();
/* now close xfer window */
XtDestroyWidget(xferData->dialog);
}
/* ********************** END OF FILE *************************/

View File

@ -435,7 +435,8 @@ Boolean
verifyBox( Widget parent, char *text )
{
Widget dialog,msgbox;
XmString message = XmStringCreateSimple(text);
/* XmString message = XmStringCreateSimple(text); */
XmString message = XmStringCreateLtoR( text, charset );
XmString yes,no;
VerifyBox verifyData;