mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
2001-06-17 Joshua Sled <jsled@asynchronous.org>
* src/engine/gnc-account-xml-v2.c (dom_tree_to_account): Added.
* src/engine/gnc-transaction-xml-v2.c (dom_tree_to_transaction):
Added.
* src/FileDialog.c: Added support for copying
scheduled-transaction-related GNCBook fields.
src/engine/
* src/engine/FreqSpec.{h,c}: Added.
* src/engine/SchedXaction.{h,c}: Added.
* src/engine/gnc-{freqspec,schedxaction}-xml-v2.c: Added
* src/engine/gnc-book.c: Added the template group [template
transaction belong to the template group] and the Scheduled
Trasnaction list.
* src/gnome/glade/sched_xact.glade: Added.
* src/gnome/dialog-nextrun.{h,c}: Added.
* src/gnome/dialog-scheduledxaction.{h,c}: Added.
* src/gnome/gnc-frequency.{h,c}: Added.
* src/SplitLedger.c, src/MultiLedger.c: Added support for a
Template Ledger.
* src/guile/gnc.gwp: Added wrapping for
dialog-{scheduledxactions,nextrun}-creation functions.
* src/register/splitreg.c: Added formula credit and debit cells,
and flags for template-register support.
* src/register/formulacell.h: Added.
* src/gnome/gnc-dateedit.h: Added explanatory comment from dave_p
in IRC.
* src/gnome/query-user.h: Added prototype of
gnc_verify_dialog_parented(...), so I could use it the SX UI
stuff.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@4725 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
3
AUTHORS
3
AUTHORS
@@ -66,6 +66,9 @@ Christian Stimming <stimming@tuhh.de> is a report-generating
|
||||
monster. He's been on of the largest contributors to the current report
|
||||
infrastructure, creating many of the important reports.
|
||||
|
||||
Joshua Sled <jsled@asynchronous.org> works on scheduled transactions
|
||||
and budgeting.
|
||||
|
||||
|
||||
Other Contributors:
|
||||
----------------
|
||||
|
||||
49
ChangeLog
49
ChangeLog
@@ -1,3 +1,50 @@
|
||||
2001-06-17 Joshua Sled <jsled@asynchronous.org>
|
||||
|
||||
* src/engine/gnc-account-xml-v2.c (dom_tree_to_account): Added.
|
||||
|
||||
* src/engine/gnc-transaction-xml-v2.c (dom_tree_to_transaction):
|
||||
Added.
|
||||
|
||||
* src/FileDialog.c: Added support for copying
|
||||
scheduled-transaction-related GNCBook fields.
|
||||
src/engine/
|
||||
|
||||
* src/engine/FreqSpec.{h,c}: Added.
|
||||
|
||||
* src/engine/SchedXaction.{h,c}: Added.
|
||||
|
||||
* src/engine/gnc-{freqspec,schedxaction}-xml-v2.c: Added
|
||||
|
||||
* src/engine/gnc-book.c: Added the template group [template
|
||||
transaction belong to the template group] and the Scheduled
|
||||
Trasnaction list.
|
||||
|
||||
* src/gnome/glade/sched_xact.glade: Added.
|
||||
|
||||
* src/gnome/dialog-nextrun.{h,c}: Added.
|
||||
|
||||
* src/gnome/dialog-scheduledxaction.{h,c}: Added.
|
||||
|
||||
* src/gnome/gnc-frequency.{h,c}: Added.
|
||||
|
||||
* src/SplitLedger.c, src/MultiLedger.c: Added support for a
|
||||
Template Ledger.
|
||||
|
||||
* src/guile/gnc.gwp: Added wrapping for
|
||||
dialog-{scheduledxactions,nextrun}-creation functions.
|
||||
|
||||
* src/register/splitreg.c: Added formula credit and debit cells,
|
||||
and flags for template-register support.
|
||||
|
||||
* src/register/formulacell.h: Added.
|
||||
|
||||
* src/gnome/gnc-dateedit.h: Added explanatory comment from dave_p
|
||||
in IRC.
|
||||
|
||||
* src/gnome/query-user.h: Added prototype of
|
||||
gnc_verify_dialog_parented(...), so I could use it the SX UI
|
||||
stuff.
|
||||
|
||||
2001-06-17 Kevin Finn <kevinfinn@mediaone.net>
|
||||
|
||||
* src/gnome/window-reconcile.c: Implemented automatic interest
|
||||
@@ -75,7 +122,7 @@
|
||||
creation druid code. Rename api calls to reflect the more
|
||||
general use of the druid.
|
||||
|
||||
2001-06-16 Robert Graham Merkel <rgmerk@mira.net
|
||||
2001-06-16 Robert Graham Merkel <rgmerk@mira.net>
|
||||
|
||||
* po/POTFILES.in : remove references to deleted files.
|
||||
|
||||
|
||||
@@ -565,6 +565,8 @@ gncFileSaveAs (void)
|
||||
{
|
||||
AccountGroup *group;
|
||||
GNCPriceDB *pdb;
|
||||
GList *sxList;
|
||||
AccountGroup *templateGroup;
|
||||
GNCBook *new_book;
|
||||
GNCBook *book;
|
||||
const char *filename;
|
||||
@@ -596,8 +598,14 @@ gncFileSaveAs (void)
|
||||
}
|
||||
|
||||
/* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
|
||||
|
||||
// FIXME: this might want to be a function of the GNCBook, since it
|
||||
// needs to sync with changes to the internals/structure of
|
||||
// GNCBook... --jsled
|
||||
group = gnc_book_get_group(book);
|
||||
pdb = gnc_book_get_pricedb(book);
|
||||
sxList = gnc_book_get_schedxactions(book);
|
||||
templateGroup = gnc_book_get_template_group(book);
|
||||
|
||||
new_book = gnc_book_new ();
|
||||
gnc_book_begin (new_book, newfile, FALSE, FALSE);
|
||||
@@ -671,6 +679,8 @@ gncFileSaveAs (void)
|
||||
/* OK, save the data to the file ... */
|
||||
gnc_book_set_group(new_book, group);
|
||||
gnc_book_set_pricedb(new_book, pdb);
|
||||
gnc_book_set_schedxactions(new_book, sxList);
|
||||
gnc_book_set_template_group(new_book, templateGroup);
|
||||
gncFileSave ();
|
||||
|
||||
g_free (newfile);
|
||||
|
||||
@@ -138,6 +138,8 @@ void gncFileQuit (void);
|
||||
|
||||
AccountGroup *gncGetCurrentGroup (void);
|
||||
|
||||
Account *gncGetTemplateAccount(void);
|
||||
|
||||
GNCBook *gncGetCurrentBook (void);
|
||||
|
||||
#endif /* __GNC_FILE_DIALOG_H__ */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#define REGISTER_SINGLE_CM_CLASS "register-single"
|
||||
#define REGISTER_SUBACCOUNT_CM_CLASS "register-subaccount"
|
||||
#define REGISTER_GL_CM_CLASS "register-gl"
|
||||
#define REGISTER_TEMPLATE_CM_CLASS "register-template"
|
||||
|
||||
|
||||
struct _xaccLedgerDisplay
|
||||
@@ -74,7 +75,8 @@ static xaccLedgerDisplay *
|
||||
xaccLedgerDisplayInternal (Account *lead_account, Query *q,
|
||||
LedgerDisplayType ld_type,
|
||||
SplitRegisterType reg_type,
|
||||
SplitRegisterStyle style);
|
||||
SplitRegisterStyle style,
|
||||
gboolean templateMode );
|
||||
static void xaccLedgerDisplayRefreshInternal (xaccLedgerDisplay *ld,
|
||||
GList *splits);
|
||||
|
||||
@@ -358,7 +360,7 @@ xaccLedgerDisplaySimple (Account *account)
|
||||
reg_type = get_reg_type (account, LD_SINGLE);
|
||||
|
||||
return xaccLedgerDisplayInternal (account, NULL, LD_SINGLE, reg_type,
|
||||
gnc_get_default_register_style ());
|
||||
gnc_get_default_register_style (), FALSE );
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
@@ -378,9 +380,11 @@ xaccLedgerDisplayAccGroup (Account *account)
|
||||
reg_type = get_reg_type (account, LD_SUBACCOUNT);
|
||||
|
||||
return xaccLedgerDisplayInternal (account, NULL, LD_SUBACCOUNT,
|
||||
reg_type, REG_STYLE_JOURNAL);
|
||||
reg_type, REG_STYLE_JOURNAL, FALSE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************\
|
||||
* xaccLedgerDisplayGL *
|
||||
* opens up a general ledger window *
|
||||
@@ -390,7 +394,7 @@ xaccLedgerDisplayAccGroup (Account *account)
|
||||
\********************************************************************/
|
||||
|
||||
xaccLedgerDisplay *
|
||||
xaccLedgerDisplayGL (void)
|
||||
xaccLedgerDisplayGL ()
|
||||
{
|
||||
Query *query;
|
||||
time_t start;
|
||||
@@ -423,7 +427,48 @@ xaccLedgerDisplayGL (void)
|
||||
|
||||
return xaccLedgerDisplayInternal (NULL, query, LD_GL,
|
||||
GENERAL_LEDGER,
|
||||
REG_STYLE_JOURNAL);
|
||||
REG_STYLE_JOURNAL, FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
* id is some identifier that can be:
|
||||
* . used in a query to look for the transaction which belong to this
|
||||
* template ledger
|
||||
* . set in a specific key value for new transactions which belong to
|
||||
* this template ledger.
|
||||
**/
|
||||
xaccLedgerDisplay *
|
||||
xaccLedgerDisplayTemplateGL( char *id )
|
||||
{
|
||||
GNCBook *book;
|
||||
Query *q;
|
||||
time_t start;
|
||||
struct tm *tm;
|
||||
xaccLedgerDisplay *ld;
|
||||
SplitRegister *sr;
|
||||
AccountGroup *ag;
|
||||
Account *acct;
|
||||
|
||||
q = xaccMallocQuery();
|
||||
|
||||
ag = gnc_book_get_template_group( gncGetCurrentBook() );
|
||||
acct = xaccGetAccountFromName( ag, id );
|
||||
if ( acct == NULL ) {
|
||||
// FIXME
|
||||
printf( "can't get template account for id \"%s\"\n", id );
|
||||
}
|
||||
xaccQueryAddSingleAccountMatch( q, acct, QUERY_AND );
|
||||
book = gncGetCurrentBook();
|
||||
xaccQuerySetGroup( q, gnc_book_get_template_group(book) );
|
||||
|
||||
ld = xaccLedgerDisplayInternal( NULL, q, LD_GL,
|
||||
GENERAL_LEDGER,
|
||||
REG_STYLE_JOURNAL,
|
||||
TRUE ); // template mode? TRUE.
|
||||
|
||||
sr = xaccLedgerDisplayGetSR( ld );
|
||||
sr->templateAcct = acct;
|
||||
return ld;
|
||||
}
|
||||
|
||||
static gncUIWidget
|
||||
@@ -541,8 +586,6 @@ refresh_handler (GHashTable *changes, gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
xaccQuerySetGroup (ld->query, gncGetCurrentGroup ());
|
||||
|
||||
splits = xaccQueryGetSplits (ld->query);
|
||||
|
||||
ledger_set_watches (ld, splits);
|
||||
@@ -590,6 +633,7 @@ make_ledger_query (xaccLedgerDisplay *ld,
|
||||
break;
|
||||
|
||||
case LD_GL:
|
||||
case LD_TEMPLATE:
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -637,14 +681,15 @@ xaccLedgerDisplay *
|
||||
xaccLedgerDisplayQuery (Query *query, SplitRegisterType type,
|
||||
SplitRegisterStyle style)
|
||||
{
|
||||
return xaccLedgerDisplayInternal (NULL, query, LD_GL, type, style);
|
||||
return xaccLedgerDisplayInternal (NULL, query, LD_GL, type, style, FALSE);
|
||||
}
|
||||
|
||||
static xaccLedgerDisplay *
|
||||
xaccLedgerDisplayInternal (Account *lead_account, Query *q,
|
||||
LedgerDisplayType ld_type,
|
||||
SplitRegisterType reg_type,
|
||||
SplitRegisterStyle style)
|
||||
SplitRegisterStyle style,
|
||||
gboolean templateMode )
|
||||
{
|
||||
xaccLedgerDisplay *ld;
|
||||
gboolean show_all;
|
||||
@@ -712,9 +757,16 @@ xaccLedgerDisplayInternal (Account *lead_account, Query *q,
|
||||
|
||||
break;
|
||||
|
||||
case LD_TEMPLATE:
|
||||
class = REGISTER_TEMPLATE_CM_CLASS;
|
||||
// FIXME: sanity checks?
|
||||
// Check for kvp-frame data?
|
||||
break;
|
||||
|
||||
default:
|
||||
PERR ("bad ledger type: %d", ld_type);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
ld = g_new (xaccLedgerDisplay, 1);
|
||||
@@ -748,24 +800,33 @@ xaccLedgerDisplayInternal (Account *lead_account, Query *q,
|
||||
|
||||
/* xaccMallocSplitRegister will malloc & initialize the register,
|
||||
* but will not do the gui init */
|
||||
view.entry_handler = xaccSRGetEntryHandler;
|
||||
view.label_handler = xaccSRGetLabelHandler;
|
||||
view.io_flag_handler = xaccSRGetIOFlagsHandler;
|
||||
view.fg_color_handler = xaccSRGetFGColorHandler;
|
||||
view.bg_color_handler = xaccSRGetBGColorHandler;
|
||||
view.cell_border_handler = xaccSRGetCellBorderHandler;
|
||||
view.confirm_handler = xaccSRConfirmHandler;
|
||||
view.handler_user_data = NULL;
|
||||
// The following handlers are changed in template mode.
|
||||
if ( templateMode ) {
|
||||
view.entry_handler = xaccSRTemplateGetEntryHandler;
|
||||
view.io_flag_handler = xaccSRTemplateGetIOFlagsHandler;
|
||||
view.confirm_handler = xaccSRTemplateConfirmHandler;
|
||||
} else {
|
||||
view.entry_handler = xaccSRGetEntryHandler;
|
||||
view.io_flag_handler = xaccSRGetIOFlagsHandler;
|
||||
view.confirm_handler = xaccSRConfirmHandler;
|
||||
}
|
||||
|
||||
ld->reg = xaccMallocSplitRegister (reg_type, style, FALSE, &view,
|
||||
xaccMLGUIDMalloc,
|
||||
xaccMLGUIDFree,
|
||||
xaccMLGUIDCopy);
|
||||
|
||||
xaccMLGUIDCopy,
|
||||
templateMode);
|
||||
xaccSRSetData (ld->reg, ld,
|
||||
xaccLedgerDisplayParent,
|
||||
xaccLedgerDisplaySetHelp);
|
||||
|
||||
ld->reg->template = templateMode;
|
||||
|
||||
splits = xaccQueryGetSplits (ld->query);
|
||||
|
||||
ledger_set_watches (ld, splits);
|
||||
@@ -825,6 +886,8 @@ xaccLedgerDisplayRefresh (xaccLedgerDisplay *ld)
|
||||
if (!ld || ld->loading)
|
||||
return;
|
||||
|
||||
//xaccQueryPrint( ld->query );
|
||||
|
||||
xaccLedgerDisplayRefreshInternal (ld, xaccQueryGetSplits (ld->query));
|
||||
}
|
||||
|
||||
@@ -859,6 +922,13 @@ xaccLedgerDisplayRefreshByReg (SplitRegister *reg)
|
||||
xaccLedgerDisplayRefresh (ld);
|
||||
return;
|
||||
}
|
||||
|
||||
ld = gnc_find_first_gui_component (REGISTER_TEMPLATE_CM_CLASS,
|
||||
find_by_reg, reg );
|
||||
if (ld)
|
||||
{
|
||||
xaccLedgerDisplayRefresh (ld);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
@@ -892,6 +962,8 @@ xaccDestroyLedgerDisplay (Account *account)
|
||||
xaccDestroyLedgerDisplayClass (account, REGISTER_SINGLE_CM_CLASS);
|
||||
xaccDestroyLedgerDisplayClass (account, REGISTER_SUBACCOUNT_CM_CLASS);
|
||||
xaccDestroyLedgerDisplayClass (account, REGISTER_GL_CM_CLASS);
|
||||
// no TEMPLATE_CM_CLASS, because it doesn't correspond to any account
|
||||
// FIXME: but there probably should be an analagous method
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "Query.h"
|
||||
#include "splitreg.h"
|
||||
#include "SplitLedger.h"
|
||||
#include "SchedXaction.h"
|
||||
#include "Transaction.h"
|
||||
|
||||
|
||||
@@ -50,7 +51,8 @@ typedef enum
|
||||
{
|
||||
LD_SINGLE,
|
||||
LD_SUBACCOUNT,
|
||||
LD_GL
|
||||
LD_GL,
|
||||
LD_TEMPLATE,
|
||||
} LedgerDisplayType;
|
||||
|
||||
|
||||
@@ -82,6 +84,16 @@ xaccLedgerDisplay * xaccLedgerDisplaySimple (Account *account);
|
||||
xaccLedgerDisplay * xaccLedgerDisplayAccGroup (Account *account);
|
||||
|
||||
xaccLedgerDisplay * xaccLedgerDisplayGL (void);
|
||||
xaccLedgerDisplay * xaccLedgerDisplayGLTemplate( char *id );
|
||||
|
||||
/**
|
||||
* Displays a template ledger.
|
||||
* This lists template Splits from the given ScheduledTransaction.
|
||||
*
|
||||
* Really, requires a GList of scheduled transactions and kvp-frame
|
||||
* data.
|
||||
**/
|
||||
xaccLedgerDisplay * xaccLedgerDisplayTemplateGL( );
|
||||
|
||||
/* display a general ledger for an arbitrary query */
|
||||
xaccLedgerDisplay * xaccLedgerDisplayQuery (Query *query,
|
||||
|
||||
@@ -195,6 +195,7 @@ struct _SRInfo
|
||||
|
||||
/* hook to set help string */
|
||||
SRSetHelpCallback set_help;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -230,8 +231,13 @@ static Transaction * xaccSRGetTrans (SplitRegister *reg,
|
||||
VirtualCellLocation vcell_loc);
|
||||
static Split * xaccSRGetCurrentTransSplit (SplitRegister *reg,
|
||||
VirtualCellLocation *vcell_loc);
|
||||
static void xaccSRActuallySaveChangedCells (SplitRegister *reg, Transaction *trans,
|
||||
Split *split, guint32 changed );
|
||||
static void xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans,
|
||||
Split *split);
|
||||
static void xaccSRSaveChangedTemplateCells (SplitRegister *reg,
|
||||
Transaction *trans,
|
||||
Split *split);
|
||||
static gboolean xaccSRFindSplit (SplitRegister *reg,
|
||||
Transaction *trans, Split *trans_split,
|
||||
Split *split, CursorClass cursor_class,
|
||||
@@ -393,7 +399,7 @@ gnc_copy_split_onto_split(Split *from, Split *to, gboolean use_cut_semantics)
|
||||
}
|
||||
|
||||
/* Uses the scheme transaction copying routines */
|
||||
static void
|
||||
void
|
||||
gnc_copy_trans_onto_trans(Transaction *from, Transaction *to,
|
||||
gboolean use_cut_semantics,
|
||||
gboolean do_commit)
|
||||
@@ -1272,7 +1278,11 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
|
||||
|
||||
info->blank_split_edited = TRUE;
|
||||
|
||||
if ( reg->template ) {
|
||||
xaccSRSaveChangedTemplateCells( reg, trans, blank_split );
|
||||
} else {
|
||||
xaccSRSaveChangedCells(reg, trans, blank_split);
|
||||
}
|
||||
|
||||
gnc_resume_gui_refresh ();
|
||||
|
||||
@@ -2673,6 +2683,8 @@ xaccSRRedrawReg (SplitRegister *reg)
|
||||
/* Copy from the register object to scheme. This needs to be
|
||||
* in sync with xaccSRSaveRegEntry and xaccSRSaveChangedCells. */
|
||||
|
||||
|
||||
// jsled: This will need to be modified, as well.
|
||||
static gboolean
|
||||
xaccSRSaveRegEntryToSCM (SplitRegister *reg, SCM trans_scm, SCM split_scm,
|
||||
gboolean use_cut_semantics)
|
||||
@@ -2815,7 +2827,9 @@ xaccSRSaveRegEntryToSCM (SplitRegister *reg, SCM trans_scm, SCM split_scm,
|
||||
|
||||
/* ======================================================== */
|
||||
/* Copy from the register object to the engine */
|
||||
|
||||
// jsled: okay... the fun.
|
||||
// actually, not really the fun, but scan this to see if anything
|
||||
// jumps out; the
|
||||
gboolean
|
||||
xaccSRSaveRegEntry (SplitRegister *reg, gboolean do_commit)
|
||||
{
|
||||
@@ -2829,6 +2843,8 @@ xaccSRSaveRegEntry (SplitRegister *reg, gboolean do_commit)
|
||||
const char *memo;
|
||||
const char *desc;
|
||||
|
||||
//DEBUG( "=== In xaccSRSaveRegEntry\n" );
|
||||
|
||||
/* get the handle to the current split and transaction */
|
||||
split = xaccSRGetCurrentSplit (reg);
|
||||
trans = xaccSRGetCurrentTrans (reg);
|
||||
@@ -2922,13 +2938,16 @@ xaccSRSaveRegEntry (SplitRegister *reg, gboolean do_commit)
|
||||
|
||||
DEBUG ("updating trans addr=%p\n", trans);
|
||||
|
||||
if ( reg->template ) {
|
||||
xaccSRSaveChangedTemplateCells( reg, trans, split );
|
||||
} else {
|
||||
xaccSRSaveChangedCells (reg, trans, split);
|
||||
}
|
||||
|
||||
memo = xaccSplitGetMemo (split);
|
||||
memo = memo ? memo : "(null)";
|
||||
desc = xaccTransGetDescription (trans);
|
||||
desc = desc ? desc : "(null)";
|
||||
|
||||
PINFO ("finished saving split %s of trans %s \n", memo, desc);
|
||||
|
||||
/* If the modified split is the "blank split", then it is now an
|
||||
@@ -3122,7 +3141,6 @@ sr_split_auto_calc (SplitRegister *reg, Split *split, guint32 changed)
|
||||
message,
|
||||
default_value,
|
||||
radio_list);
|
||||
|
||||
for (node = radio_list; node; node = node->next)
|
||||
g_free (node->data);
|
||||
|
||||
@@ -3190,14 +3208,149 @@ sr_split_auto_calc (SplitRegister *reg, Split *split, guint32 changed)
|
||||
/* ======================================================== */
|
||||
|
||||
static void
|
||||
xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
||||
xaccSRSaveChangedTemplateCells( SplitRegister *reg,
|
||||
Transaction *trans,
|
||||
Split *split )
|
||||
{
|
||||
SRInfo *info = xaccSRGetInfo( reg );
|
||||
Split *other_split = NULL;
|
||||
guint32 changed;
|
||||
kvp_frame *kvpf;
|
||||
AccountGroup *template_ag;
|
||||
Account *template_acc;
|
||||
kvp_value *tag_val;
|
||||
|
||||
DEBUG( "=== In xaccSRSaveChangedTemplateCells\n" );
|
||||
|
||||
//template_acc = gncGetTemplateAccount();
|
||||
//template_ag = gnc_book_get_template_group( gncGetCurrentBook() );
|
||||
template_acc = reg->templateAcct;
|
||||
|
||||
changed = xaccSplitRegisterGetChangeFlag( reg );
|
||||
changed |= xaccSplitRegisterGetConditionalChangeFlag( reg );
|
||||
if ( (MOD_DATE & changed) ||
|
||||
(MOD_NUM & changed) ||
|
||||
(MOD_RECN & changed) )
|
||||
{
|
||||
PERR( "unexpected changed field in a template register: %32x\n", changed );
|
||||
}
|
||||
|
||||
// We'll be using the Split's KVP frame a lot...
|
||||
kvpf = xaccSplitGetSlots( split );
|
||||
|
||||
if ( MOD_XFRM & changed )
|
||||
{
|
||||
// FIXME: This should probably do the same checks as
|
||||
// xaccSRSaveChangedCells regarding account types
|
||||
// [between different currency accounts, mainly]
|
||||
char *new_name;
|
||||
Account *acct;
|
||||
AccountGroup *acctGrp;
|
||||
GUID *acctGUID;
|
||||
|
||||
// save the account GUID into the kvp_data.
|
||||
new_name = reg->xfrmCell->cell.value;
|
||||
acctGrp = gnc_book_get_group( gncGetCurrentBook() );
|
||||
acct = xaccGetAccountFromFullName( acctGrp, new_name,
|
||||
gnc_get_account_separator() );
|
||||
if ( acct == NULL ) {
|
||||
PERR( "unknown group \"%s\"\n", new_name );
|
||||
return;
|
||||
}
|
||||
acctGUID = (const GUID *)xaccAccountGetGUID( acct );
|
||||
kvp_frame_set_slot( kvpf, "sched-xaction/xfrm",
|
||||
kvp_value_new_guid( acctGUID ) );
|
||||
kvpf = xaccSplitGetSlots( split );
|
||||
changed ^= MOD_XFRM;
|
||||
// +DEBUG
|
||||
if ( 0 ) {
|
||||
GList *foo = xaccAccountGetSplitList( template_acc );
|
||||
if ( foo ) {
|
||||
printf( "Splits:\n" );
|
||||
do {
|
||||
printf ("\tsplit: \"%s\"\n", xaccSplitGetMemo( (Split*)foo->data ) );
|
||||
} while ( (foo = foo->next) );
|
||||
} else {
|
||||
printf( "No Splits.\n" );
|
||||
}
|
||||
}
|
||||
// -DEBUG
|
||||
|
||||
// set the actual account to the fake account for
|
||||
// these templates...
|
||||
xaccAccountInsertSplit (template_acc, split);
|
||||
|
||||
// +DEBUG
|
||||
if ( 0 ) {
|
||||
GList *foo = xaccAccountGetSplitList( template_acc );
|
||||
if ( foo ) {
|
||||
printf( "Splits:\n" );
|
||||
do {
|
||||
printf ("\tsplit: \"%s\"\n", xaccSplitGetMemo( (Split*)foo->data ) );
|
||||
} while ( (foo = foo->next) );
|
||||
} else {
|
||||
printf( "No Splits.\n" );
|
||||
}
|
||||
}
|
||||
// -DEBUG
|
||||
|
||||
}
|
||||
if ( MOD_MXFRM & changed )
|
||||
{
|
||||
// DTRT
|
||||
DEBUG( "Template: Got MOD_MXFRM changed\n" );
|
||||
changed ^= MOD_MXFRM;
|
||||
}
|
||||
if ( MOD_AMNT & changed )
|
||||
{
|
||||
char *amountStr = "x + y/42";
|
||||
gnc_numeric new_amount;
|
||||
gnc_numeric credit;
|
||||
gnc_numeric debit;
|
||||
|
||||
//credit = xaccGetPriceCellValue(reg->creditCell);
|
||||
//debit = xaccGetPriceCellValue(reg->debitCell);
|
||||
//new_amount = gnc_numeric_sub_fixed (debit, credit);
|
||||
|
||||
// FIXME: the credit/debit cells are limited to
|
||||
// numeric values by definition [and code]. Blegh.
|
||||
DEBUG( "kvp_frame before: %s\n", kvp_frame_to_string( kvpf ) );
|
||||
//amountStr = gnc_numeric_to_string( new_amount );
|
||||
kvp_frame_set_slot( kvpf, "sched-xaction/credit_formula",
|
||||
kvp_value_new_string( reg->formCreditCell->cell.value ) );
|
||||
kvp_frame_set_slot( kvpf, "sched-xaction/debit_formula",
|
||||
kvp_value_new_string( reg->formDebitCell->cell.value ) );
|
||||
DEBUG( "kvp_frame after: %s\n", kvp_frame_to_string( kvpf ) );
|
||||
changed ^= MOD_AMNT;
|
||||
// set the amount to an innocuous value
|
||||
xaccSplitSetValue (split, gnc_numeric_create(0, 1) );
|
||||
}
|
||||
if ( MOD_SHRS & changed )
|
||||
{
|
||||
char *sharesStr = "(x + y)/42";
|
||||
|
||||
// FIXME: shares cells are numeric by definition.
|
||||
DEBUG( "kvp_frame before: %s\n", kvp_frame_to_string( kvpf ) );
|
||||
|
||||
//sharesStr = gnc_numeric_to_string( sharesStr );
|
||||
kvp_frame_set_slot( kvpf, "sched-xaction/shares",
|
||||
kvp_value_new_string( sharesStr ) );
|
||||
DEBUG( "kvp_frame after: %s\n", kvp_frame_to_string( kvpf ) );
|
||||
// set the shares to an innocuous value
|
||||
xaccSplitSetSharePriceAndAmount (split,
|
||||
gnc_numeric_create(0, 1),
|
||||
gnc_numeric_create(0, 1) );
|
||||
changed ^= MOD_SHRS;
|
||||
}
|
||||
|
||||
xaccSRActuallySaveChangedCells( reg, trans, split, changed );
|
||||
}
|
||||
|
||||
static void
|
||||
xaccSRActuallySaveChangedCells( SplitRegister *reg, Transaction *trans, Split *split, guint32 changed )
|
||||
{
|
||||
SRInfo *info = xaccSRGetInfo (reg);
|
||||
Split *other_split = NULL;
|
||||
|
||||
/* copy the contents from the cursor to the split */
|
||||
if (MOD_DATE & changed)
|
||||
@@ -3214,7 +3367,6 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
||||
|
||||
xaccTransSetDateTS (trans, &ts);
|
||||
}
|
||||
|
||||
if (MOD_NUM & changed)
|
||||
{
|
||||
DEBUG ("MOD_NUM: %s\n",
|
||||
@@ -3273,6 +3425,10 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
||||
* a two-line display, we want to reparent the "other" split, but
|
||||
* only if there is one. XFRM is the straight split, MXFRM is the
|
||||
* mirrored split. */
|
||||
|
||||
// jsled: this is where it starts to get fun. in the template
|
||||
// register, we save the XFRM account in the kvp frame.
|
||||
// also, when loading, we load from the kvp data.
|
||||
if (MOD_XFRM & changed)
|
||||
{
|
||||
Account *old_acc;
|
||||
@@ -3473,6 +3629,22 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
||||
xaccSplitScrub (other_split);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
|
||||
{
|
||||
SRInfo *info = xaccSRGetInfo (reg);
|
||||
Split *other_split = NULL;
|
||||
guint32 changed;
|
||||
|
||||
changed = xaccSplitRegisterGetChangeFlag (reg);
|
||||
changed |= xaccSplitRegisterGetConditionalChangeFlag (reg);
|
||||
|
||||
// all the code in xaccSRActuallySaveChangedCells was right here,
|
||||
// before. -- jsled
|
||||
xaccSRActuallySaveChangedCells( reg, trans, split, changed );
|
||||
}
|
||||
|
||||
/* ======================================================== */
|
||||
@@ -3632,6 +3804,125 @@ use_security_cells (SplitRegister *reg, VirtualLocation virt_loc)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *
|
||||
xaccSRTemplateGetEntryHandler( VirtualLocation virt_loc,
|
||||
gboolean translate,
|
||||
gboolean *conditionally_changed,
|
||||
gpointer user_data )
|
||||
{
|
||||
SplitRegister *reg = user_data;
|
||||
const char *value = "";
|
||||
CellType cell_type;
|
||||
Transaction *trans;
|
||||
Split *split;
|
||||
kvp_frame *kvpf;
|
||||
GUID *tmpguid;
|
||||
|
||||
//DEBUG( "In xaccSRTemplateGetEntryHandler\n" );
|
||||
|
||||
cell_type = xaccSplitRegisterGetCellType (reg, virt_loc);
|
||||
|
||||
split = sr_get_split (reg, virt_loc.vcell_loc);
|
||||
if (split == NULL)
|
||||
{
|
||||
return xaccSRGetEntryHandler( virt_loc, translate,
|
||||
conditionally_changed, user_data );
|
||||
}
|
||||
|
||||
|
||||
trans = xaccSplitGetParent (split);
|
||||
kvpf = xaccSplitGetSlots( split );
|
||||
|
||||
switch (cell_type) {
|
||||
case XFRM_CELL:
|
||||
{
|
||||
static char *name = NULL;
|
||||
char account_separator;
|
||||
|
||||
if ( kvpf != NULL ) {
|
||||
DEBUG( "kvp_frame: %s\n", kvp_frame_to_string( kvpf ) );
|
||||
tmpguid = kvp_value_get_guid( kvp_frame_get_slot( kvpf,
|
||||
"sched-xaction/xfrm" ) );
|
||||
DEBUG( "Got the guid \"%s\"\n", guid_to_string( tmpguid ) );
|
||||
account_separator = gnc_get_account_separator();
|
||||
DEBUG( "foo\n" );
|
||||
name = xaccAccountGetFullName (xaccAccountLookup( tmpguid ),
|
||||
account_separator);
|
||||
DEBUG( "bar\n" );
|
||||
|
||||
DEBUG( "Got the full name: %s\n", name );
|
||||
} else {
|
||||
name = "";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
break;
|
||||
case CRED_CELL:
|
||||
case DEBT_CELL:
|
||||
{
|
||||
char *amtStr;
|
||||
gnc_numeric amount;
|
||||
|
||||
if ( kvpf != NULL ) {
|
||||
amtStr = kvp_value_get_string( kvp_frame_get_slot( kvpf,
|
||||
"sched-xaction/amnt" ) );
|
||||
amount = gnc_numeric_create( 0, 1 );
|
||||
string_to_gnc_numeric( amtStr, &amount );
|
||||
|
||||
if (gnc_numeric_zero_p (amount))
|
||||
return "";
|
||||
|
||||
if (gnc_numeric_negative_p (amount) && (cell_type == DEBT_CELL))
|
||||
return "";
|
||||
|
||||
if (gnc_numeric_positive_p (amount) && (cell_type == CRED_CELL))
|
||||
return "";
|
||||
|
||||
amount = gnc_numeric_abs (amount);
|
||||
|
||||
//return xaccPrintAmount (amount,
|
||||
//gnc_split_value_print_info (split, FALSE));
|
||||
|
||||
// jsled_FIXME: This should be fixed
|
||||
// to be correct for the "fake" account.
|
||||
return xaccPrintAmount( amount,
|
||||
gnc_default_print_info( FALSE ) );
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FCRED_CELL:
|
||||
{
|
||||
char *formulaStr;
|
||||
if ( kvpf != NULL ) {
|
||||
return kvp_value_get_string( kvp_frame_get_slot( kvpf,
|
||||
"sched-xaction/credit_formula" ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FDEBT_CELL:
|
||||
{
|
||||
char *formulaStr;
|
||||
if ( kvpf != NULL ) {
|
||||
return kvp_value_get_string( kvp_frame_get_slot( kvpf,
|
||||
"sched-xaction/debit_formula" ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MXFRM_CELL:
|
||||
{
|
||||
return "FIXME:MXFRM";
|
||||
}
|
||||
break;
|
||||
} // end switch
|
||||
return xaccSRGetEntryHandler( virt_loc,
|
||||
translate,
|
||||
conditionally_changed,
|
||||
user_data );
|
||||
}
|
||||
|
||||
const char *
|
||||
xaccSRGetEntryHandler (VirtualLocation virt_loc, gboolean translate,
|
||||
gboolean *conditionally_changed, gpointer user_data)
|
||||
@@ -3796,8 +4087,6 @@ xaccSRGetEntryHandler (VirtualLocation virt_loc, gboolean translate,
|
||||
{
|
||||
static char *name = NULL;
|
||||
|
||||
g_free (name);
|
||||
|
||||
name = xaccAccountGetFullName (xaccSplitGetAccount (split),
|
||||
account_separator);
|
||||
|
||||
@@ -3868,8 +4157,6 @@ xaccSRGetEntryHandler (VirtualLocation virt_loc, gboolean translate,
|
||||
Split *s = xaccSplitGetOtherSplit (split);
|
||||
static char *name = NULL;
|
||||
|
||||
g_free (name);
|
||||
|
||||
if (s)
|
||||
name = xaccAccountGetFullName (xaccSplitGetAccount (s),
|
||||
account_separator);
|
||||
@@ -4108,6 +4395,11 @@ xaccSRGetLabelHandler (VirtualLocation virt_loc, gpointer user_data)
|
||||
case NOTES_CELL:
|
||||
return _("Notes");
|
||||
|
||||
case FCRED_CELL:
|
||||
return _("Credit Formula");
|
||||
case FDEBT_CELL:
|
||||
return _("Debit Formula");
|
||||
|
||||
case NO_CELL:
|
||||
return "";
|
||||
|
||||
@@ -4120,6 +4412,15 @@ xaccSRGetLabelHandler (VirtualLocation virt_loc, gpointer user_data)
|
||||
return "";
|
||||
}
|
||||
|
||||
CellIOFlags
|
||||
xaccSRTemplateGetIOFlagsHandler( VirtualLocation virt_loc,
|
||||
gpointer user_data )
|
||||
{
|
||||
//printf( "In xaccSRTemplateGetIOFlagsHandler\n" );
|
||||
return xaccSRGetIOFlagsHandler( virt_loc,
|
||||
user_data );
|
||||
}
|
||||
|
||||
CellIOFlags
|
||||
xaccSRGetIOFlagsHandler (VirtualLocation virt_loc, gpointer user_data)
|
||||
{
|
||||
@@ -4139,6 +4440,8 @@ xaccSRGetIOFlagsHandler (VirtualLocation virt_loc, gpointer user_data)
|
||||
case MEMO_CELL:
|
||||
case MXFRM_CELL:
|
||||
case NOTES_CELL:
|
||||
case FCRED_CELL:
|
||||
case FDEBT_CELL:
|
||||
return XACC_CELL_ALLOW_ALL;
|
||||
|
||||
case CRED_CELL:
|
||||
@@ -4356,7 +4659,9 @@ xaccSRGetBGColorHandler (VirtualLocation virt_loc,
|
||||
if ((cell_type != DEBT_CELL) &&
|
||||
(cell_type != CRED_CELL) &&
|
||||
(cell_type != TDEBT_CELL) &&
|
||||
(cell_type != TCRED_CELL))
|
||||
(cell_type != TCRED_CELL) &&
|
||||
(cell_type != FCRED_CELL) &&
|
||||
(cell_type != FDEBT_CELL) )
|
||||
*hatching = FALSE;
|
||||
else
|
||||
{
|
||||
@@ -4439,6 +4744,14 @@ xaccSRGetBGColorHandler (VirtualLocation virt_loc,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccSRTemplateConfirmHandler( VirtualLocation virt_loc,
|
||||
gpointer user_data )
|
||||
{
|
||||
//DEBUG( "In xaccSRConfirmHandler\n" );
|
||||
return xaccSRConfirmHandler( virt_loc, user_data );
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccSRConfirmHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data)
|
||||
|
||||
@@ -166,6 +166,8 @@ void xaccSRLoadRegister (SplitRegister *reg, GList * slist,
|
||||
* a refresh will result in a new blank transaction.
|
||||
* The method returns TRUE if something was changed. */
|
||||
gboolean xaccSRSaveRegEntry (SplitRegister *reg, gboolean do_commit);
|
||||
gboolean xaccSRTemplateSaveRegEntry (SplitRegister *reg,
|
||||
gboolean do_commit);
|
||||
|
||||
/* The xaccSRRedrawReg() method should be called soon
|
||||
* after the xaccSRSaveRegEntry() method. It checks the
|
||||
@@ -209,10 +211,16 @@ const char * xaccSRGetEntryHandler (VirtualLocation virt_loc,
|
||||
gboolean translate,
|
||||
gboolean *changed,
|
||||
gpointer user_data);
|
||||
const char * xaccSRTemplateGetEntryHandler (VirtualLocation virt_loc,
|
||||
gboolean translate,
|
||||
gboolean *changed,
|
||||
gpointer user_data);
|
||||
const char * xaccSRGetLabelHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
CellIOFlags xaccSRGetIOFlagsHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
CellIOFlags xaccSRTemplateGetIOFlagsHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
guint32 xaccSRGetFGColorHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
guint32 xaccSRGetBGColorHandler (VirtualLocation virt_loc,
|
||||
@@ -223,5 +231,14 @@ void xaccSRGetCellBorderHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
gboolean xaccSRConfirmHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
gboolean xaccSRTemplateConfirmHandler (VirtualLocation virt_loc,
|
||||
gpointer user_data);
|
||||
|
||||
// jsled-added 2001.05.19 for export to dialog-nextrun.c [which will
|
||||
// change its name at some point]
|
||||
void gnc_copy_trans_onto_trans(Transaction *from, Transaction *to,
|
||||
gboolean use_cut_semantics,
|
||||
gboolean do_commit);
|
||||
|
||||
|
||||
#endif /* __XACC_SPLIT_LEDGER_H__ */
|
||||
|
||||
144
src/doc/TODO-schedxactions
Normal file
144
src/doc/TODO-schedxactions
Normal file
@@ -0,0 +1,144 @@
|
||||
Author: jsled@asynchronous.org
|
||||
|
||||
Main Scheduled Transaction todo list
|
||||
------------------------------------
|
||||
|
||||
. Engine ...Init() functions should be private.
|
||||
. FreqSpec.c
|
||||
. xaccFreqSpecGetFreqStr [display] needs to go away
|
||||
|
||||
. finish the GNCFrequency widget
|
||||
. finish/recreate restoring UI state from FreqSpec.
|
||||
X add the ...GetFreqStr() code for the complex composite FreqSpecs
|
||||
X fix the ...GetNextInstance() code
|
||||
X XMLv2 I/O
|
||||
X create a template register
|
||||
X store account and amount data in kvp_frames.
|
||||
. find a way to list multiple registers for template transaction purposes.
|
||||
. this is a "normal" general ledger + a "stock" general ledger
|
||||
. this is going to be: a tabbed notebook in which the tabs contain
|
||||
the number of transactions the GL they hold contain.
|
||||
X need policy for start-dates in GNCFrequency
|
||||
X fix GetNextInstance and GetInstanceAfter, mostly for composite FreqSpecs
|
||||
X also needs to deal with >28-mday values WRT last-occur date + multipliers
|
||||
|
||||
. add a big calendar [gnome-pim? evo?] SXaction List code
|
||||
. match existing transactions for long-time users
|
||||
. based off template-transaction data, some big existing-transaction
|
||||
scanning code.
|
||||
. need "since-last-run" UI for instanatiation.
|
||||
. create transactions
|
||||
X numeric
|
||||
. formula
|
||||
. need variable fill-in UI...
|
||||
. re-use gnome-sheet code for a variable-binding table?
|
||||
. register mods
|
||||
. to see upcoming xactions, modifying future balance
|
||||
. to instantiate xactions.
|
||||
. to note which are "recurring"
|
||||
. the mozilla "reload" glyph is kinda neat...
|
||||
. would like "don't even tell me you instantiated it, just fscking do
|
||||
it!" option for non-manual-conf SXes
|
||||
. deal better with formulas in template transactions [real FormulaCell]
|
||||
. recognize purely numeric template transactions and balance at
|
||||
template-creation time.
|
||||
. GNCFrequency
|
||||
. weekly options
|
||||
. restoring FreqSpec into GNCFrequency UI
|
||||
. initial-settings synchronization [start date, optionmenus]
|
||||
. backend support
|
||||
. PostgreSQL
|
||||
. others?
|
||||
|
||||
|
||||
Enhancements:
|
||||
. SX name should be default value for template transaction description
|
||||
. loan/repayment SX's
|
||||
. integrate "Financial Calculator"
|
||||
. auto-determine number of occurances/end condition from liability
|
||||
account amount.
|
||||
|
||||
========================================
|
||||
|
||||
Template Registers/Transactions
|
||||
|
||||
Template-option registers are used for users to enter the template
|
||||
transaction to be created when the scheduled transaction comes due.
|
||||
Most fields will be copied directly, but certain fields will need to
|
||||
be modified upon instantiation, and the template version of these
|
||||
transactions will need to contain the information necessary to do that
|
||||
instiantion. For some fields, this will be a derivable quantity, and
|
||||
for others the user will need to be prompted. This will show up
|
||||
mostly for the amount of variable-amount transactions; perhaps the
|
||||
amount is then derivable from some external source. These amounts
|
||||
will then be represented by a variable, a function, or a formula
|
||||
including both.
|
||||
|
||||
Examples...
|
||||
|
||||
Verizon bill: "108.83 +- x"
|
||||
. x: tax amounts [user-input]
|
||||
Power: "seasonal_util_gas( 'OAK_CA', '100 therms' ) + seasonal_util_elec( 'OAK_CA', '220 kwhrs' )"
|
||||
. seasonal_util_gas( loc, amt ): regional/seasonal power price
|
||||
. seasonal_util_elec( loc, amt ): regional/seasonal electricity price
|
||||
Rent: 1900
|
||||
Phone: "26"
|
||||
Internet: "80 - 40 - 10" [3 splits]
|
||||
Daily: "4 + 6 (+ 26)"
|
||||
. 4: cigarettes
|
||||
. 6: avg lunch
|
||||
. (opt) 20: wine
|
||||
Gas: "regional_auto_gas( 'BERK_CA', 'premium', 14 gal +- 2 )"
|
||||
. regional_gas( loc, type, formula )
|
||||
. loc: location
|
||||
. type: subclass of gasoline
|
||||
. formula: formula to use for user-query
|
||||
TROA: "220.14"
|
||||
|
||||
User-input
|
||||
|
||||
When user input is required for scheduled transaction instantiation,
|
||||
we should have some sort of simple, spreadsheet-like UI for the entry
|
||||
and verification of values. This would allow the entry of all values
|
||||
necessary for the formula to be calculated.
|
||||
|
||||
We also need a way to defer instantiation of a scheduled transaction
|
||||
until the information can be obtained.
|
||||
|
||||
Example...
|
||||
|
||||
type | date | formula | variable | value | total
|
||||
+---------------------------------------------------------------------------+
|
||||
| PG&E | 2001.04.12 | lookup(x) + lookup| | | 184 |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | x | 142 | |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | y | 42 | |
|
||||
|---------------------------------------------------------------------------|
|
||||
| gas | 2001.03.01 | cost/gal * gal | | | |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | cost/gal | 1.949 | 14.27 |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | gal | 12.32 | |
|
||||
|---------------------------------------------------------------------------|
|
||||
| gas | 2001.03.12 | cost/gal * gal | | | |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | cost/gal | 1.959 | 15.39 |
|
||||
|---------------------------------------------------------------------------|
|
||||
| | | | gal | 13.43 | |
|
||||
+---------------------------------------------------------------------------+
|
||||
|
||||
I believe this means we can use the existing gnc-sheet/register-style
|
||||
thingy.
|
||||
|
||||
We probably want to defer the lookup-based stuff until
|
||||
1.8/2.0/gnumatic-provided network backing for this.
|
||||
|
||||
Stocks/recurring share purchases can make use of this, as well. The
|
||||
idea is then, probably, that the user will have a fixed amount with
|
||||
which to buy as many shares as possible; the num-shares, then, is a
|
||||
formula based on a lookup at the given time [the share price],
|
||||
involving the function FLOOR.
|
||||
|
||||
It'd be nice if this formula could be either a simple infix syntax for
|
||||
normal people, or a sexp for Schemers.
|
||||
812
src/engine/FreqSpec.c
Normal file
812
src/engine/FreqSpec.c
Normal file
@@ -0,0 +1,812 @@
|
||||
/********************************************************************\
|
||||
* FreqSpec.c -- Frequency specifier implementation. *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/********************************************************************\
|
||||
Current status
|
||||
All kinds of repeats work, including composites. This is tested -
|
||||
although composites need some more test cases to be put into the test
|
||||
suite - ../test/test-freq-spec.c
|
||||
FreqSpec objects are currently 'set' to give them the information
|
||||
they need. Separate methods for modifying currently existing FreqSpec
|
||||
objects are not provided. In the case of composites, you may add FreqSpec
|
||||
objects to a composite, and you may access a list of the FreqSpec objects
|
||||
which form the composite. This interface allows you to do damage...
|
||||
|
||||
TODO list
|
||||
Ben Stanley 2001-04-02
|
||||
* Write xaccFreqSpecGetFreqStr (I wonder how this will be
|
||||
internationalised... I suspect that this code will need to be
|
||||
re-written for each language, because the code will have to
|
||||
generate grammar... It's more than just translating strings.)
|
||||
However, the first priority is to write one that works for
|
||||
English.
|
||||
* Write a function to allow you to query whether a given
|
||||
date forms part of the recurrence.
|
||||
* Write a method to get the previous recurrence
|
||||
* provide XML Load/Save functionality for this object.
|
||||
* Figure out xaccFreqSpecIsValidDate - I suspect that this is the
|
||||
'query whether a given date forms part of the recurrence'
|
||||
above.
|
||||
* FIGURE OUT WHAT'S GOING ON WITH xaccFreqSpecGetUIType AND
|
||||
xaccFreqSpecSetUIType.
|
||||
* Try to reduce the size of the data structure. There are quite a few
|
||||
32 bit fields which could be stored in about 8 bits.
|
||||
* Add public methods to allow for recurrences with an interval
|
||||
of 1 to be set without reference to an initial 'date' - monthly
|
||||
things in particular. Try to reduce the dependence on an initial
|
||||
date for the input to set up the recurrence.
|
||||
|
||||
Questions:
|
||||
Is it best that the public interface stay as GDate, or should it
|
||||
really be a timespec? I have no problem with converting GDates to
|
||||
timespecs for load/save if that makes life easier.
|
||||
|
||||
However, I chose to use GDate internally because I have used a *lot*
|
||||
of the date calculating ability of GDate in the internal implementation.
|
||||
GDate has simplified this work enormously compared to using struct tm
|
||||
and time_t. The engine's timespec object doesn't appear to have the
|
||||
required functionality either, so I would need to write the required
|
||||
functions for timespec (perhaps by implementing in terms of GDate?).
|
||||
|
||||
Hopefully it's not too painful to leave GDate in the public interface
|
||||
and change other code to use it.
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* #include <time.h> // should be config'd */
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreqSpecP.h"
|
||||
#include "GNCIdP.h"
|
||||
/*#include "Transaction.h"*/
|
||||
/*#include "TransactionP.h"*/
|
||||
#include "date.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-event-p.h"
|
||||
#include "messages.h"
|
||||
|
||||
/* I have done this to prevent compiler warnings...
|
||||
* This is used to convert a const GDate* to a GDate* for passing
|
||||
* to the glib g_date_xxx functions which don't use const...
|
||||
* Strangely, most of the rest of glib does use const, so
|
||||
* perhaps this will change? When it does, just define this macro to
|
||||
* nothing and the compiler will check the constness of each pointer....
|
||||
*/
|
||||
#define CONST_HACK (GDate*)
|
||||
|
||||
static short module = MOD_SX;
|
||||
|
||||
/** PROTOTYPES ******************************************************/
|
||||
|
||||
/**
|
||||
* Destroys all sub-FreqSpecs in a composite FreqSpec.
|
||||
* Assertion error if it's not a COMPOSITE FreqSpec.
|
||||
**/
|
||||
void xaccFreqSpecCompositesClear( FreqSpec *fs );
|
||||
|
||||
void subSpecsListMapDelete( gpointer data, gpointer user_data );
|
||||
|
||||
/** Local data defs *****/
|
||||
|
||||
/**
|
||||
* The number of days in each month.
|
||||
**/
|
||||
struct monthDesc {
|
||||
char *dshort;
|
||||
char *dlong;
|
||||
gint numDays;
|
||||
};
|
||||
|
||||
/* This stuff is going to need i18n.
|
||||
* wouldn't it be simpler to use the system
|
||||
* date conversion functions?
|
||||
* glib already knows about this. */
|
||||
static char *weekDayNames[] = {
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
};
|
||||
|
||||
/* hmmm... glib already knows all about this. */
|
||||
struct monthDesc monthInfo[] = {
|
||||
#define M_JAN 0
|
||||
{ "Jan", "January", 31 },
|
||||
#define M_FEB 1
|
||||
{ "Feb", "February", 28 },
|
||||
#define M_MAR 2
|
||||
{ "Mar", "March", 31 },
|
||||
#define M_APR 3
|
||||
{ "Apr", "April", 30 },
|
||||
#define M_MAY 4
|
||||
{ "May", "May", 31 },
|
||||
#define M_JUN 5
|
||||
{ "Jun", "June", 30 },
|
||||
#define M_JUL 6
|
||||
{ "Jul", "July", 31 },
|
||||
#define M_AUG 7
|
||||
{ "Aug", "August", 31 },
|
||||
#define M_SEP 8
|
||||
{ "Sep", "September", 30 },
|
||||
#define M_OCT 9
|
||||
{ "Oct", "October", 31 },
|
||||
#define M_NOV 10
|
||||
{ "Nov", "November", 30 },
|
||||
#define M_DEC 11
|
||||
{ "Dec", "December", 31 }
|
||||
};
|
||||
|
||||
/** Local Prototypes *****/
|
||||
|
||||
FreqSpec*
|
||||
xaccFreqSpecMalloc()
|
||||
{
|
||||
FreqSpec *fs = g_new0(FreqSpec, 1);
|
||||
xaccFreqSpecInit( fs );
|
||||
// FIXME:event
|
||||
gnc_engine_generate_event( &fs->guid, GNC_EVENT_CREATE );
|
||||
return fs;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecInit( FreqSpec *fs )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
xaccGUIDNew( &fs->guid );
|
||||
xaccStoreEntity( fs, &fs->guid, GNC_ID_FREQSPEC );
|
||||
fs->type = INVALID;
|
||||
fs->uift = UIFREQ_ONCE;
|
||||
memset( &(fs->s), 0, sizeof(fs->s) );
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecCleanUp( FreqSpec *fs )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
switch ( fs->type ) {
|
||||
case INVALID:
|
||||
case ONCE:
|
||||
case DAILY:
|
||||
case WEEKLY:
|
||||
case MONTHLY:
|
||||
case MONTH_RELATIVE:
|
||||
break;
|
||||
case COMPOSITE:
|
||||
xaccFreqSpecCompositesClear( fs );
|
||||
g_list_free( fs->s.composites.subSpecs );
|
||||
break;
|
||||
default:
|
||||
g_return_if_fail(FALSE);
|
||||
}
|
||||
fs->type = INVALID;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecFree( FreqSpec *fs )
|
||||
{
|
||||
if ( fs == NULL ) return;
|
||||
gnc_engine_generate_event( &fs->guid, GNC_EVENT_DESTROY );
|
||||
xaccRemoveEntity( &fs->guid );
|
||||
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
|
||||
g_free( fs );
|
||||
}
|
||||
|
||||
FreqType
|
||||
xaccFreqSpecGetType( FreqSpec *fs )
|
||||
{
|
||||
g_return_val_if_fail( fs, INVALID );
|
||||
/* Is this really a fail? */
|
||||
g_return_val_if_fail( fs->type != INVALID, INVALID );
|
||||
return fs->type;
|
||||
}
|
||||
|
||||
|
||||
UIFreqType
|
||||
xaccFreqSpecGetUIType( FreqSpec *fs )
|
||||
{
|
||||
g_return_val_if_fail( fs, INVALID );
|
||||
return fs->uift;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetUIType( FreqSpec *fs, UIFreqType newUIFreqType )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
fs->uift = newUIFreqType;
|
||||
}
|
||||
|
||||
/*
|
||||
void
|
||||
xaccFreqSpecSetTypes( FreqSpec *fs, FreqType newFT, UIFreqType newUIFT )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
xaccFreqSpecSetType( fs, newFT );
|
||||
xaccFreqSpecSetUIType( fs, newUIFT );
|
||||
}
|
||||
*/
|
||||
|
||||
static inline guint32 min( guint32 a, guint32 b )
|
||||
{
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecGetNextInstance(
|
||||
FreqSpec *fs,
|
||||
const GDate* in_date,
|
||||
GDate* out_date )
|
||||
{
|
||||
GList *list, *blist;
|
||||
int mon;
|
||||
|
||||
g_return_if_fail( fs );
|
||||
switch( fs->type ) {
|
||||
case INVALID:
|
||||
g_return_if_fail(FALSE);
|
||||
|
||||
case ONCE:
|
||||
if ( g_date_compare( &(fs->s.once.date), CONST_HACK in_date ) > 0 ) {
|
||||
*out_date = fs->s.once.date;
|
||||
} else {
|
||||
/* Date is past due. Return an invalid date. */
|
||||
g_date_clear( out_date, 1 );
|
||||
}
|
||||
break;
|
||||
|
||||
case DAILY: {
|
||||
guint32 julian_in_date, julian_next_repeat, complete_intervals;
|
||||
julian_in_date = g_date_julian( CONST_HACK in_date );
|
||||
complete_intervals =
|
||||
(julian_in_date - fs->s.daily.offset_from_epoch) /
|
||||
fs->s.daily.interval_days;
|
||||
julian_next_repeat =
|
||||
fs->s.daily.offset_from_epoch +
|
||||
(complete_intervals + 1) * fs->s.daily.interval_days;
|
||||
g_date_set_julian( out_date, julian_next_repeat );
|
||||
} break;
|
||||
|
||||
case WEEKLY: {
|
||||
/* This implementation stores the offset from epoch as the number
|
||||
* of days, not week epoch offset and day in week offset.
|
||||
* It is very similar to the daily repeat representation. */
|
||||
guint32 julian_in_date, julian_next_repeat, complete_intervals;
|
||||
julian_in_date = g_date_julian( CONST_HACK in_date );
|
||||
complete_intervals =
|
||||
(julian_in_date - fs->s.weekly.offset_from_epoch) /
|
||||
(fs->s.weekly.interval_weeks * 7);
|
||||
julian_next_repeat =
|
||||
fs->s.weekly.offset_from_epoch +
|
||||
(complete_intervals + 1) * fs->s.weekly.interval_weeks * 7;
|
||||
g_date_set_julian( out_date, julian_next_repeat );
|
||||
|
||||
/* This code passes the test, but it seems large and complicated...
|
||||
* it uses a separate week offset from epoch and day in week offset. */
|
||||
/* guint32 julian_in_date, julian_next_repeat, complete_intervals,
|
||||
in_weeks_from_epoch, after_repeat_in_week_interval;
|
||||
julian_in_date = g_date_julian( CONST_HACK in_date );
|
||||
in_weeks_from_epoch = (julian_in_date-1) / 7;
|
||||
complete_intervals =
|
||||
(in_weeks_from_epoch -
|
||||
fs->s.weekly.offset_from_epoch) /
|
||||
fs->s.weekly.interval_weeks;
|
||||
after_repeat_in_week_interval =
|
||||
((julian_in_date-1) % 7 >= fs->s.weekly.day_of_week ||
|
||||
(in_weeks_from_epoch - fs->s.weekly.offset_from_epoch) %
|
||||
fs->s.weekly.interval_weeks > 0 ) ? 1 : 0;
|
||||
julian_next_repeat =
|
||||
(fs->s.weekly.offset_from_epoch +
|
||||
(complete_intervals + after_repeat_in_week_interval) *
|
||||
fs->s.weekly.interval_weeks) * 7 +
|
||||
fs->s.weekly.day_of_week + 1;
|
||||
g_date_set_julian( out_date, julian_next_repeat );
|
||||
*/
|
||||
} break;
|
||||
|
||||
case MONTHLY: {
|
||||
guint32 in_months_from_epoch, after_repeat_in_month_interval,
|
||||
complete_intervals, next_repeat_months_from_epoch, month, year;
|
||||
in_months_from_epoch = (g_date_year( CONST_HACK in_date )-1) * 12 +
|
||||
g_date_month( CONST_HACK in_date ) - 1;
|
||||
complete_intervals =
|
||||
(in_months_from_epoch - fs->s.monthly.offset_from_epoch) /
|
||||
fs->s.monthly.interval_months;
|
||||
after_repeat_in_month_interval =
|
||||
(g_date_day( CONST_HACK in_date ) >= fs->s.monthly.day_of_month ||
|
||||
(in_months_from_epoch - fs->s.monthly.offset_from_epoch) %
|
||||
fs->s.monthly.interval_months > 0 ||
|
||||
g_date_day( CONST_HACK in_date ) >=
|
||||
g_date_days_in_month( g_date_month( CONST_HACK in_date ),
|
||||
g_date_year( CONST_HACK in_date ) ) ) ? 1 : 0;
|
||||
next_repeat_months_from_epoch =
|
||||
fs->s.monthly.offset_from_epoch +
|
||||
(complete_intervals + after_repeat_in_month_interval) *
|
||||
fs->s.monthly.interval_months;
|
||||
/* Hmmm... what happens if the day of the month is greater than the
|
||||
* number of days in this month?
|
||||
* Here I have constrained the day of the month by the number
|
||||
* of days in the month. This is compensated for above by checking if
|
||||
* the input day is the last day of that month, in which case it will
|
||||
* move to the next month interval.
|
||||
*/
|
||||
month = next_repeat_months_from_epoch % 12 + 1;
|
||||
year = next_repeat_months_from_epoch / 12 + 1;
|
||||
g_date_set_dmy( out_date,
|
||||
min( fs->s.monthly.day_of_month,
|
||||
g_date_days_in_month( month, year ) ),
|
||||
month,
|
||||
year );
|
||||
} break;
|
||||
|
||||
case MONTH_RELATIVE: {
|
||||
guint32 in_months_from_epoch, after_repeat_in_month_interval,
|
||||
complete_intervals, next_repeat_months_from_epoch, month, year,
|
||||
wday_of_1st, day_of_repeat;
|
||||
GDate date1;
|
||||
in_months_from_epoch = (g_date_year( CONST_HACK in_date )-1) * 12 +
|
||||
g_date_month( CONST_HACK in_date ) - 1;
|
||||
complete_intervals =
|
||||
(in_months_from_epoch - fs->s.month_relative.offset_from_epoch) /
|
||||
fs->s.month_relative.interval_months;
|
||||
month = g_date_month( CONST_HACK in_date );
|
||||
year = g_date_year( CONST_HACK in_date );
|
||||
g_date_set_dmy( &date1, 1, month, year );
|
||||
wday_of_1st = g_date_weekday( &date1 );
|
||||
day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
|
||||
((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
|
||||
after_repeat_in_month_interval =
|
||||
(g_date_day( CONST_HACK in_date ) >= day_of_repeat ||
|
||||
day_of_repeat > g_date_days_in_month( month, year ) ||
|
||||
(in_months_from_epoch - fs->s.month_relative.offset_from_epoch) %
|
||||
fs->s.month_relative.interval_months > 0 ) ? 1 : 0;
|
||||
next_repeat_months_from_epoch =
|
||||
fs->s.month_relative.offset_from_epoch +
|
||||
(complete_intervals + after_repeat_in_month_interval) *
|
||||
fs->s.month_relative.interval_months;
|
||||
month = next_repeat_months_from_epoch % 12 + 1;
|
||||
year = next_repeat_months_from_epoch / 12 + 1;
|
||||
g_date_set_dmy( &date1, 1, month, year );
|
||||
wday_of_1st = g_date_weekday( &date1 );
|
||||
/* This calculates the day of the month in the month which forms
|
||||
* the next month in the cycle after the given input date.
|
||||
* However, this day may be larger than the number of days in that month... */
|
||||
day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
|
||||
((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
|
||||
while( day_of_repeat > g_date_days_in_month( month, year ) ) {
|
||||
/* If the repeat occurs after the end of the month, then
|
||||
* find the next month containing a day which satisfies the request.
|
||||
* Each candiate month separated by interval_months is considered
|
||||
* by this loop.*/
|
||||
++complete_intervals;
|
||||
next_repeat_months_from_epoch =
|
||||
fs->s.month_relative.offset_from_epoch +
|
||||
complete_intervals * fs->s.month_relative.interval_months;
|
||||
month = next_repeat_months_from_epoch % 12 + 1;
|
||||
year = next_repeat_months_from_epoch / 12 + 1;
|
||||
g_date_set_dmy( &date1, 1, month, year );
|
||||
wday_of_1st = g_date_weekday( &date1 );
|
||||
day_of_repeat = (fs->s.month_relative.occurrence-1)*7 +
|
||||
((fs->s.month_relative.weekday + 7 - wday_of_1st)%7 + 1);
|
||||
/* Hmmm... It would be nice to know that this loop is
|
||||
* guaranteed to terminate... CHECK ME! */
|
||||
}
|
||||
g_date_set_dmy( out_date, day_of_repeat, month, year );
|
||||
} break;
|
||||
|
||||
case COMPOSITE:
|
||||
list = fs->s.composites.subSpecs;
|
||||
if ( !list ) {
|
||||
/* sets date to be invalid */
|
||||
g_date_clear( out_date, 1 );
|
||||
break;
|
||||
}
|
||||
{
|
||||
/* This implements || composites. */
|
||||
guint32 min_julian = 0xFFFFFFFF; /* the biggest unsigned 32 bit number */
|
||||
guint32 this_julian;
|
||||
do {
|
||||
GDate next_repeat;
|
||||
xaccFreqSpecGetNextInstance(
|
||||
(FreqSpec*) list->data,
|
||||
in_date,
|
||||
&next_repeat );
|
||||
this_julian = g_date_julian( &next_repeat );
|
||||
|
||||
min_julian = min( min_julian, this_julian );
|
||||
|
||||
} while ( (list = g_list_next(list)) );
|
||||
g_date_set_julian( out_date, min_julian );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_date_clear( out_date, 1 );
|
||||
g_return_if_fail(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char*
|
||||
xaccFreqSpecIsValidDateRelaxed( FreqSpec *fs, time_t query )
|
||||
{
|
||||
return "FIXME: not implemented yet!";
|
||||
}
|
||||
*/
|
||||
|
||||
void
|
||||
xaccFreqSpecSetOnceDate( FreqSpec *fs, const GDate* when )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( when );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
fs->type = ONCE;
|
||||
fs->s.once.date = *when;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetDaily( FreqSpec *fs,
|
||||
const GDate* initial_date,
|
||||
guint interval_days )
|
||||
{
|
||||
guint32 julian_days_since_epoch;
|
||||
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_days > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
fs->type = DAILY;
|
||||
fs->s.daily.interval_days = interval_days;
|
||||
|
||||
julian_days_since_epoch = g_date_julian( CONST_HACK initial_date );
|
||||
fs->s.daily.offset_from_epoch = julian_days_since_epoch % interval_days;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetWeekly( FreqSpec *fs,
|
||||
const GDate* initial_date,
|
||||
guint interval_weeks )
|
||||
{
|
||||
/* pick one... make sure that the code in next matches this,
|
||||
* and that the fields in the
|
||||
* weekly struct match too.
|
||||
*/
|
||||
#if 0
|
||||
/* *
|
||||
* This implements weekly by using the fact that 1 week = 7 days.
|
||||
* Weeks start at epoch in this representation, not necesarily Monday,
|
||||
* so there is not really any difference...
|
||||
* The weekly tests pass.
|
||||
*/
|
||||
guint32 julian_days_since_epoch;
|
||||
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_weeks > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
|
||||
fs->type = DAILY;
|
||||
fs->s.daily.interval_days = 7 * interval_weeks;
|
||||
|
||||
julian_days_since_epoch = g_date_julian( CONST_HACK initial_date );
|
||||
fs->s.daily.offset_from_epoch = julian_days_since_epoch % (7*interval_weeks);
|
||||
#endif
|
||||
#if 1
|
||||
/* simplest solution */
|
||||
guint32 julian_days_since_epoch;
|
||||
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_weeks > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
|
||||
fs->type = WEEKLY;
|
||||
fs->s.weekly.interval_weeks = interval_weeks;
|
||||
|
||||
julian_days_since_epoch = g_date_julian( CONST_HACK initial_date );
|
||||
fs->s.weekly.offset_from_epoch = julian_days_since_epoch % (7*interval_weeks);
|
||||
#endif
|
||||
#if 0
|
||||
/**
|
||||
* Use the weekly implementation, which seems to be more complicated...
|
||||
* uses separate weekly and day in week offsets.
|
||||
* works.
|
||||
*/
|
||||
guint32 julian_day_initial, weeks_since_epoch;
|
||||
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_weeks > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
|
||||
fs->type = WEEKLY;
|
||||
fs->s.weekly.interval_weeks = interval_weeks;
|
||||
|
||||
julian_day_initial = g_date_julian( CONST_HACK initial_date );
|
||||
weeks_since_epoch = (julian_day_initial-1) / 7;
|
||||
fs->s.weekly.day_of_week = (julian_day_initial-1) % 7;
|
||||
fs->s.weekly.offset_from_epoch = weeks_since_epoch % interval_weeks;
|
||||
|
||||
g_return_if_fail( 0 <= fs->s.weekly.day_of_week );
|
||||
g_return_if_fail( fs->s.weekly.day_of_week < 7 );
|
||||
g_return_if_fail( fs->s.weekly.offset_from_epoch < interval_weeks );
|
||||
g_return_if_fail( 0 <= fs->s.weekly.offset_from_epoch );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetMonthly( FreqSpec *fs,
|
||||
const GDate* initial_date,
|
||||
guint interval_months )
|
||||
{
|
||||
guint months_since_epoch;
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_months > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
fs->type = MONTHLY;
|
||||
fs->s.monthly.interval_months = interval_months;
|
||||
|
||||
months_since_epoch = (g_date_year( CONST_HACK initial_date )-1) * 12 +
|
||||
g_date_month( CONST_HACK initial_date ) - 1;
|
||||
fs->s.monthly.offset_from_epoch = months_since_epoch % interval_months;
|
||||
fs->s.monthly.day_of_month = g_date_day( CONST_HACK initial_date );
|
||||
|
||||
g_return_if_fail( fs->s.monthly.offset_from_epoch <
|
||||
fs->s.monthly.interval_months );
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetMonthRelative( FreqSpec *fs,
|
||||
const GDate* initial_date,
|
||||
guint interval_months )
|
||||
{
|
||||
guint months_since_epoch;
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( interval_months > 0 );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
fs->type = MONTH_RELATIVE;
|
||||
fs->s.month_relative.interval_months = interval_months;
|
||||
|
||||
months_since_epoch = (g_date_year( CONST_HACK initial_date )-1) * 12 +
|
||||
g_date_month( CONST_HACK initial_date ) - 1;
|
||||
fs->s.month_relative.offset_from_epoch = months_since_epoch % interval_months;
|
||||
|
||||
fs->s.month_relative.weekday = g_date_weekday( CONST_HACK initial_date );
|
||||
fs->s.month_relative.occurrence = (g_date_day( CONST_HACK initial_date )-1) / 7 + 1;
|
||||
|
||||
g_return_if_fail( fs->s.month_relative.weekday > 0 );
|
||||
g_return_if_fail( fs->s.month_relative.weekday <= 7 );
|
||||
g_return_if_fail( fs->s.month_relative.occurrence > 0 );
|
||||
g_return_if_fail( fs->s.month_relative.occurrence <= 5 );
|
||||
g_return_if_fail( fs->s.month_relative.offset_from_epoch <
|
||||
fs->s.month_relative.interval_months );
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecSetComposite( FreqSpec *fs )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
xaccFreqSpecCleanUp( fs );
|
||||
fs->type = COMPOSITE;
|
||||
fs->s.composites.subSpecs = NULL;
|
||||
}
|
||||
|
||||
GList*
|
||||
xaccFreqSpecCompositeGet( FreqSpec *fs )
|
||||
{
|
||||
g_return_val_if_fail( fs, NULL );
|
||||
g_return_val_if_fail( fs->type == COMPOSITE, NULL );
|
||||
return fs->s.composites.subSpecs;
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecCompositeAdd( FreqSpec *fs, FreqSpec *fsToAdd )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
g_return_if_fail( fs->type == COMPOSITE );
|
||||
fs->s.composites.subSpecs =
|
||||
g_list_append( fs->s.composites.subSpecs, fsToAdd );
|
||||
}
|
||||
|
||||
void
|
||||
subSpecsListMapDelete( gpointer data, gpointer user_data )
|
||||
{
|
||||
xaccFreqSpecFree( (FreqSpec*)data );
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecCompositesClear( FreqSpec *fs )
|
||||
{
|
||||
g_return_if_fail( fs->type == COMPOSITE );
|
||||
g_list_foreach( fs->s.composites.subSpecs,
|
||||
subSpecsListMapDelete, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str )
|
||||
{
|
||||
GList *list;
|
||||
FreqSpec *tmpFS;
|
||||
int tmpInt;
|
||||
char *tmpStr;
|
||||
int i;
|
||||
|
||||
// FIXME: fill in.
|
||||
switch( xaccFreqSpecGetUIType( fs ) ) {
|
||||
case UIFREQ_ONCE:
|
||||
tmpStr = g_new0( char, 25 );
|
||||
// this is now a GDate.
|
||||
g_date_strftime( tmpStr, 25,
|
||||
"%a, %b %e, %Y",
|
||||
&fs->s.once.date );
|
||||
g_string_sprintf( str, "Once: %s", tmpStr );
|
||||
g_free( tmpStr );
|
||||
break;
|
||||
|
||||
case UIFREQ_DAILY:
|
||||
g_string_sprintf( str, "Daily" );
|
||||
if ( fs->s.daily.interval_days > 1 ) {
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.daily.interval_days );
|
||||
}
|
||||
break;
|
||||
|
||||
case UIFREQ_DAILY_MF:
|
||||
g_string_sprintf( str, "Daily [M-F]" );
|
||||
if ( fs->s.weekly.interval_weeks > 1 ) {
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.weekly.interval_weeks );
|
||||
}
|
||||
break;
|
||||
|
||||
case UIFREQ_WEEKLY:
|
||||
g_string_sprintf( str, "Weekly" );
|
||||
tmpInt = -1;
|
||||
tmpStr = g_new0( char, 8 );
|
||||
for ( i=0; i<7; i++ ) {
|
||||
tmpStr[i] = '-';
|
||||
}
|
||||
|
||||
list = xaccFreqSpecCompositeGet( fs );
|
||||
do {
|
||||
tmpFS = (FreqSpec*)list->data;
|
||||
if ( xaccFreqSpecGetType(tmpFS) != WEEKLY ) {
|
||||
g_string_sprintf( str,
|
||||
"error: UIFREQ_WEEKLY doesn't contain weekly children" );
|
||||
return;
|
||||
}
|
||||
if ( tmpInt == -1 ) {
|
||||
tmpInt = tmpFS->s.weekly.interval_weeks;
|
||||
}
|
||||
// put the first letter of the weekday name in
|
||||
// the appropriate position.
|
||||
|
||||
// FIXME: need the offset from the day-of-week
|
||||
// of the Julian epoch
|
||||
/*
|
||||
tmpStr[tmpFS->specData.dateAnchor[1]] =
|
||||
weekDayNames[tmpFS->specData.dateAnchor[1]][0];
|
||||
*/
|
||||
} while ( (list = g_list_next(list)) );
|
||||
|
||||
if ( tmpInt > 1 ) {
|
||||
g_string_sprintfa( str, " (x%d)", tmpInt );
|
||||
}
|
||||
g_string_sprintfa( str, ": %s", tmpStr );
|
||||
g_free( tmpStr );
|
||||
break;
|
||||
|
||||
case UIFREQ_SEMI_MONTHLY:
|
||||
g_string_sprintf( str, "Semi-Monthly" );
|
||||
list = xaccFreqSpecCompositeGet( fs );
|
||||
tmpFS = (FreqSpec*)(g_list_nth( list, 0 )->data);
|
||||
if ( tmpFS->s.monthly.interval_months > 1 ) {
|
||||
g_string_sprintfa( str, " (x%u)", tmpFS->s.monthly.interval_months );
|
||||
}
|
||||
g_string_sprintfa( str, ": " );
|
||||
if ( tmpFS->s.monthly.day_of_month > 31 ) {
|
||||
g_string_sprintfa( str, "%s", "last day" );
|
||||
} else {
|
||||
g_string_sprintfa( str, "%u", tmpFS->s.monthly.day_of_month );
|
||||
}
|
||||
g_string_sprintfa( str, ", " );
|
||||
tmpFS = (FreqSpec*)(g_list_nth( list, 1 )->data);
|
||||
if ( tmpFS->s.monthly.day_of_month > 31 ) {
|
||||
g_string_sprintfa( str, "%s", "last day" );
|
||||
} else {
|
||||
g_string_sprintfa( str, "%u", tmpFS->s.monthly.day_of_month );
|
||||
}
|
||||
break;
|
||||
|
||||
case UIFREQ_MONTHLY:
|
||||
g_string_sprintf( str, "Monthly" );
|
||||
if ( fs->s.monthly.interval_months > 1 ) {
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.monthly.interval_months );
|
||||
}
|
||||
g_string_sprintfa( str, ": %u",
|
||||
fs->s.monthly.day_of_month );
|
||||
break;
|
||||
|
||||
case UIFREQ_QUARTERLY:
|
||||
g_string_sprintf( str, "Quarterly" );
|
||||
if ( fs->s.monthly.interval_months != 3 ) {
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.monthly.interval_months/3 );
|
||||
}
|
||||
g_string_sprintfa( str, ": %u",
|
||||
fs->s.monthly.day_of_month );
|
||||
break;
|
||||
|
||||
case UIFREQ_TRI_ANUALLY:
|
||||
g_string_sprintf( str, "Tri-Anually" );
|
||||
if ( fs->s.monthly.interval_months != 4 ) {
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.monthly.interval_months/4 );
|
||||
}
|
||||
g_string_sprintfa( str, ": %u",
|
||||
fs->s.monthly.day_of_month );
|
||||
break;
|
||||
|
||||
case UIFREQ_SEMI_YEARLY:
|
||||
g_string_sprintf( str, "Semi-Yearly" );
|
||||
if ( fs->s.monthly.interval_months != 6 ) {
|
||||
if ( (fs->s.monthly.interval_months % 6) != 0 ) {
|
||||
// FIXME:error
|
||||
printf( "ERROR: FreqSpec Semi-Yearly month-interval "
|
||||
"is not a multiple of 6 [%d]",
|
||||
fs->s.monthly.interval_months );
|
||||
}
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.monthly.interval_months/6 );
|
||||
}
|
||||
g_string_sprintfa( str, ": %u",
|
||||
fs->s.monthly.day_of_month );
|
||||
break;
|
||||
|
||||
case UIFREQ_YEARLY:
|
||||
g_string_sprintf( str, "Yearly" );
|
||||
if ( fs->s.monthly.interval_months != 12 ) {
|
||||
if ( (fs->s.monthly.interval_months % 12) != 0 ) {
|
||||
// FIXME:error
|
||||
printf( "ERROR: \"Yearly\" FreqSpec month-interval "
|
||||
"is not a multiple of 12 [%d]",
|
||||
fs->s.monthly.interval_months );
|
||||
}
|
||||
g_string_sprintfa( str, " (x%u)",
|
||||
fs->s.monthly.interval_months/12 );
|
||||
}
|
||||
g_string_sprintfa( str, ": %s/%u",
|
||||
// FIXME: need the year-of-month value.
|
||||
monthInfo[/*fs->specData.dateAnchor[2]*/ 0].dshort,
|
||||
fs->s.monthly.day_of_month );
|
||||
break;
|
||||
|
||||
default:
|
||||
g_string_sprintf( str, "Unknown" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
242
src/engine/FreqSpec.h
Normal file
242
src/engine/FreqSpec.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/********************************************************************\
|
||||
* FreqSpec.h -- Frequency Specification *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef XACC_FREQSPEC_H
|
||||
#define XACC_FREQSPEC_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "GNCId.h"
|
||||
|
||||
/**
|
||||
* Frequency specification.
|
||||
*
|
||||
**/
|
||||
typedef enum gncp_FreqType {
|
||||
INVALID,
|
||||
ONCE,
|
||||
DAILY,
|
||||
WEEKLY, /* Hmmm... This is sort of DAILY[7]... */
|
||||
// BI_WEEKLY: weekly[2]
|
||||
// SEMI_MONTHLY: use composite
|
||||
MONTHLY,
|
||||
MONTH_RELATIVE,
|
||||
// YEARLY: monthly[12]
|
||||
COMPOSITE,
|
||||
} FreqType;
|
||||
|
||||
/**
|
||||
* The user's conception of the frequency. It is expected that this
|
||||
* list will grow, while the former [FreqType] will not.
|
||||
*
|
||||
* Ideally this is not here, but what can you do?
|
||||
**/
|
||||
typedef enum gncp_UIFreqType {
|
||||
UIFREQ_NONE,
|
||||
UIFREQ_ONCE,
|
||||
UIFREQ_DAILY,
|
||||
UIFREQ_DAILY_MF,
|
||||
UIFREQ_WEEKLY,
|
||||
UIFREQ_BI_WEEKLY,
|
||||
UIFREQ_SEMI_MONTHLY,
|
||||
UIFREQ_MONTHLY,
|
||||
UIFREQ_QUARTERLY,
|
||||
UIFREQ_TRI_ANUALLY,
|
||||
UIFREQ_SEMI_YEARLY,
|
||||
UIFREQ_YEARLY,
|
||||
UIFREQ_NUM_UI_FREQSPECS
|
||||
} UIFreqType;
|
||||
|
||||
/**
|
||||
* Forward declaration of FreqSpec type for storing
|
||||
* date repetition information. This is an opaque type.
|
||||
*/
|
||||
|
||||
struct gncp_freq_spec;
|
||||
typedef struct gncp_freq_spec FreqSpec;
|
||||
|
||||
|
||||
/** PROTOTYPES ******************************************************/
|
||||
|
||||
/**
|
||||
* Allocates memory for a FreqSpec.
|
||||
* Calls xaccFreqSpecInit() to initialise.
|
||||
**/
|
||||
FreqSpec* xaccFreqSpecMalloc();
|
||||
|
||||
/**
|
||||
* Initializes a FreqSpec by setting it's to type INVALID.
|
||||
* Use this to initialise a stack object.
|
||||
* FreqSpec objects must be initalised before being used by
|
||||
* any other method.
|
||||
**/
|
||||
void xaccFreqSpecInit( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* destroys any private data belonging to the FreqSpec.
|
||||
* Use this for a stack object.
|
||||
*/
|
||||
void xaccFreqSpecCleanUp( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Frees a heap allocated FreqSpec.
|
||||
* This is the opposite of xaccFreqSpecMalloc().
|
||||
**/
|
||||
void xaccFreqSpecFree( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Gets the type of a FreqSpec.
|
||||
**/
|
||||
FreqType xaccFreqSpecGetType( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Sets the type of a FreqSpec.
|
||||
* Setting the type re-initializes any spec-data; this means
|
||||
* destroying any sub-types in the case of COMPOSITE.
|
||||
* THESE FUNCTIONS HAVE NOT BEEN MAINTAINED THROUGH BEN'S CHANGES.
|
||||
* They need to be checked.
|
||||
**/
|
||||
/* void xaccFreqSpecSetType( FreqSpec *fs, FreqType newType ); */
|
||||
|
||||
UIFreqType xaccFreqSpecGetUIType( FreqSpec *fs );
|
||||
void xaccFreqSpecSetUIType( FreqSpec *fs, UIFreqType newUIFreqType );
|
||||
|
||||
/* Convenience function; calls the two above. */
|
||||
/* void xaccFreqSpecSetTypes( FreqSpec *fs, FreqType newType, UIFreqType newUIType ); */
|
||||
|
||||
/**
|
||||
* Sets the type to once-off, and initialises the
|
||||
* date it occurs on.
|
||||
* Disposes of any previous data.
|
||||
*/
|
||||
void xaccFreqSpecSetOnceDate( FreqSpec *fs,
|
||||
const GDate* when );
|
||||
|
||||
/**
|
||||
* Sets the type to DAILY. Disposes of any previous data.
|
||||
* Uses the start date to figure
|
||||
* out how many days after epoch (1/1/1900) this repeat would
|
||||
* have first occurred on if it had been running back then.
|
||||
* This is used later to figure out absolute repeat dates.
|
||||
*/
|
||||
void xaccFreqSpecSetDaily( FreqSpec *fs,
|
||||
const GDate* initial_date,
|
||||
guint interval_days );
|
||||
|
||||
/**
|
||||
* Sets the type to WEEKLY. Disposes of any previous data.
|
||||
* Uses the inital date to figure out the day of the week to use.
|
||||
*/
|
||||
void xaccFreqSpecSetWeekly( FreqSpec *fs,
|
||||
const GDate* inital_date,
|
||||
guint interval_weeks );
|
||||
|
||||
/**
|
||||
* Sets the type to MONTHLY. Disposes of any previous data.
|
||||
* Uses the inital date to figure out the day of the month to use.
|
||||
*/
|
||||
void xaccFreqSpecSetMonthly( FreqSpec *fs,
|
||||
const GDate* inital_date,
|
||||
guint interval_months );
|
||||
|
||||
/**
|
||||
* Sets the type to MONTH_RELATIVE. Disposes of any previous data.
|
||||
* Uses the inital date to figure out the day of the month to use.
|
||||
*/
|
||||
void xaccFreqSpecSetMonthRelative( FreqSpec *fs,
|
||||
const GDate* inital_date,
|
||||
guint interval_months );
|
||||
|
||||
/**
|
||||
* Sets the type to COMPOSITE. Disposes of any previous data.
|
||||
* You must Add some repeats to the composite before using
|
||||
* it for repeating.
|
||||
*/
|
||||
void xaccFreqSpecSetComposite( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Returns a human-readable string of the Frequency. This uses
|
||||
* UIFreqType to unroll the internal structure. It is an assertion
|
||||
* failure if the FreqSpec data doesn't match the UIFreqType.
|
||||
* Caller allocates the GString [natch].
|
||||
**/
|
||||
void xaccFreqSpecGetFreqStr( FreqSpec *fs, GString *str );
|
||||
|
||||
/**
|
||||
* Returns the list of FreqSpecs in a COMPOSITE FreqSpec.
|
||||
* It is an error to use this if the type is not COMPOSITE.
|
||||
* The caller should not modify this list;
|
||||
* only add/remove composites and use this fn to get
|
||||
* the perhaps-changed list head.
|
||||
**/
|
||||
GList* xaccFreqSpecCompositeGet( FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Adds a FreqSpec to the list in a COMPOSITE FreqSpec; if the
|
||||
* FreqSpec is not COMPOSITE, this is an assertion failure.
|
||||
**/
|
||||
void xaccFreqSpecCompositeAdd( FreqSpec *fs, FreqSpec *fsToAdd );
|
||||
|
||||
/**
|
||||
* Returns the next date which the FreqSpec specifies given the
|
||||
* previous occurance. Like the relaxed validity check, this doesn't
|
||||
* take multipliers into account; it just returns the next possible
|
||||
* occurance after the given day.
|
||||
* bstanley I think this should be private.
|
||||
**/
|
||||
/*
|
||||
time_t xaccFreqSpecGetInstanceAfter( FreqSpec *fs, time_t after );
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the next instance of the FreqSpec after a given input date.
|
||||
* Note that if the given date happens to be a repeat date,
|
||||
* then the next repeat date will be returned.
|
||||
**/
|
||||
void xaccFreqSpecGetNextInstance( FreqSpec *fs,
|
||||
const GDate* in_date,
|
||||
GDate* out_date );
|
||||
|
||||
/**
|
||||
* Returns either NULL [valid] or a descriptive string [reason not
|
||||
* valid] for the given query date. This is "relaxed", in that it
|
||||
* doesn't care about the frequency multiplier [e.g., For
|
||||
* WEEKLY[2]:Wed, all Wednesdays are valid; for MONTHLY[12]:16, the
|
||||
* 16th day of every month is valid.
|
||||
**/
|
||||
/*
|
||||
char* xaccFreqSpecIsValidDateRelaxed( FreqSpec *fs, time_t query );
|
||||
*/
|
||||
|
||||
/**
|
||||
* A strict validity check. Given a previous and query date, returns
|
||||
* NULL if the query date is valid, or a text reason if not.
|
||||
**/
|
||||
/*
|
||||
char* xaccFreqSpecIsValidDate( FreqSpec *fs, time_t previous, time_t query );
|
||||
*/
|
||||
|
||||
#endif /* XACC_FREQSPEC_H */
|
||||
128
src/engine/FreqSpecP.h
Normal file
128
src/engine/FreqSpecP.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/********************************************************************\
|
||||
* FreqSpec.h -- Frequency Specification *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/********************************************************************\
|
||||
This file contains private definitions and should not be used by
|
||||
other parts of the engine. This is private data and is subject to
|
||||
change.
|
||||
Currently the only files which include this file are:
|
||||
FreqSpec.c
|
||||
gnc-freqspec-xml-v2.c
|
||||
\********************************************************************/
|
||||
#ifndef XACC_FREQSPECP_H
|
||||
#define XACC_FREQSPECP_H
|
||||
|
||||
#include "FreqSpec.h"
|
||||
|
||||
/**
|
||||
* Scheduled transactions have a frequency defined by a frequency
|
||||
* specifier. This specifier, given a start date, end date [present
|
||||
* in the scheduled transaction] and last occurance date [possibly not
|
||||
* present] can be used to determine that a s.transaction should be
|
||||
* instantiated on a given date [the given query date].
|
||||
*
|
||||
* There is a split between the UIFreqType and the 'internal' FreqType
|
||||
* to reduce the complexity of some of the code involved.
|
||||
*
|
||||
* Hmmm... having this in the private header file actually prevents
|
||||
* client code from allocating this 'class' on the stack.
|
||||
* Is that a problem?
|
||||
*
|
||||
* This still needs to deal with:
|
||||
* . exceptions
|
||||
* . yearly 360/365?
|
||||
* . re-based frequencies [based around a non-standard [read:
|
||||
* not-Jan-1-based/fiscal] year]
|
||||
* . "business days" -- m-f sans holidays [per-user list thereof]
|
||||
**/
|
||||
struct gncp_freq_spec {
|
||||
FreqType type;
|
||||
UIFreqType uift;
|
||||
union u {
|
||||
struct {
|
||||
GDate date; /** The date on which the single event occurs. */
|
||||
} once;
|
||||
struct {
|
||||
guint interval_days; /** number of days from one repeat to the next. */
|
||||
guint offset_from_epoch; /** epoch is defined by glib to be 1/1/1. Offset measured in days. 0 <= offset < interval */
|
||||
} daily;
|
||||
struct {
|
||||
/* A week here is measured as 7 days. The first week starts at epoch.
|
||||
* 1/1/1 was a ?. */
|
||||
guint interval_weeks; /** number of weeks from one repeat to the next. */
|
||||
guint offset_from_epoch; /* offset measured in days.
|
||||
* This combines the week
|
||||
* offset and the day of the
|
||||
* week offset. */
|
||||
/* guint offset_from_epoch;*/ /* offset measured in weeks, 0 <= offset < interval */
|
||||
/* guint day_of_week;*/ /* I'm not sure what days each value represents, but it's not important. */
|
||||
} weekly;
|
||||
struct {
|
||||
guint interval_months; /** number of months from one repeat to the next. */
|
||||
guint offset_from_epoch; /* offset measured in months */
|
||||
guint day_of_month; /* Which day of the month it occurs on. */
|
||||
} monthly;
|
||||
struct {
|
||||
guint interval_months; /** Number of months from one repeat to the next. */
|
||||
guint offset_from_epoch; /* offset measured in months */
|
||||
guint weekday; /* stores a value equivalent to a GDateWeekday. */
|
||||
guint occurrence; /* the 1st occurrence to the 5th occurrence. */
|
||||
} month_relative;
|
||||
struct {
|
||||
/** A list of specs for a composite freq. */
|
||||
GList *subSpecs;
|
||||
} composites;
|
||||
/**
|
||||
* The dateAnchor anchors the spec to determinable days.
|
||||
*
|
||||
* ONCE:
|
||||
* dA[0] contains time_t
|
||||
* DAILY:
|
||||
* dA[0] contains day multiplier
|
||||
* dA[1] contains offset from epoch.
|
||||
* WEEKLY:
|
||||
* dA[0] contains week multiplier
|
||||
* dA[1] contains 0..6 [sun-based]
|
||||
* SEMI_MONTHLY: bstanley disused...
|
||||
* dA[0] contains month multiplier
|
||||
* dA[1] contains the first date-of-month,
|
||||
* dA[2] the second.
|
||||
* MONTHLY:
|
||||
* dA[0] contains month multiplier
|
||||
* dA[1] contains the date-of-month
|
||||
* MONTH_RELATIVE:
|
||||
* dA[0] continas month multiplier
|
||||
* dA[1] contains week number [1..5, 6=="last"]
|
||||
* [1..5 is really 1..4.428 [31/7], but it's a UI issue]
|
||||
* dA[2] contains 0..6 [sun-based day of week]
|
||||
* COMPOSITE:
|
||||
* ... list ...
|
||||
* RELATIVE:
|
||||
* ... don't know yet ...
|
||||
**/
|
||||
} s;
|
||||
GUID guid;
|
||||
};
|
||||
|
||||
#endif /* XACC_FREQSPECP_H */
|
||||
@@ -53,7 +53,9 @@ typedef enum
|
||||
GNC_ID_TRANS,
|
||||
GNC_ID_SPLIT,
|
||||
GNC_ID_PRICE,
|
||||
LAST_GNC_ID = GNC_ID_PRICE
|
||||
GNC_ID_SCHEDXACTION,
|
||||
GNC_ID_FREQSPEC,
|
||||
LAST_GNC_ID = GNC_ID_FREQSPEC
|
||||
} GNCIdType;
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,11 @@ libgncengine_la_SOURCES = \
|
||||
sixtp-to-dom-parser.c \
|
||||
sixtp-utils.c \
|
||||
sixtp-xml-write-utils.c \
|
||||
sixtp.c
|
||||
sixtp.c \
|
||||
FreqSpec.c \
|
||||
SchedXaction.c \
|
||||
gnc-freqspec-xml-v2.c \
|
||||
gnc-schedxaction-xml-v2.c
|
||||
|
||||
libgncengine_la_LDFLAGS = -version-info 2:3:1
|
||||
|
||||
@@ -107,7 +111,9 @@ noinst_HEADERS = \
|
||||
sixtp-utils.h \
|
||||
sixtp-writers.h \
|
||||
sixtp-xml-write-utils.h \
|
||||
sixtp.h
|
||||
sixtp.h \
|
||||
FreqSpec.h \
|
||||
SchedXaction.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
.cvsignore \
|
||||
|
||||
316
src/engine/SchedXaction.c
Normal file
316
src/engine/SchedXaction.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/********************************************************************\
|
||||
* SchedXaction.c -- Scheduled Transaction implementation. *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SchedXaction.h"
|
||||
#include "FreqSpec.h"
|
||||
#include "GNCIdP.h"
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
#include "date.h"
|
||||
#include "gnc-engine-util.h"
|
||||
#include "gnc-event-p.h"
|
||||
#include "messages.h"
|
||||
#include "Account.h"
|
||||
#include "Group.h"
|
||||
#include "guid.h"
|
||||
#include "gnc-book.h"
|
||||
#include "FileDialog.h"
|
||||
|
||||
static short module = MOD_SX;
|
||||
|
||||
/** Local data defs *****/
|
||||
void transactionListMapDelete( gpointer data, gpointer user_data );
|
||||
|
||||
/** Local Prototypes *****/
|
||||
|
||||
SchedXaction*
|
||||
xaccSchedXactionMalloc( GNCBook *book )
|
||||
{
|
||||
SchedXaction *sx;
|
||||
sx = g_new0( SchedXaction, 1 );
|
||||
xaccSchedXactionInit( sx, book );
|
||||
gnc_engine_generate_event( &sx->guid, GNC_EVENT_CREATE );
|
||||
return sx;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionInit( SchedXaction *sx, GNCBook *book )
|
||||
{
|
||||
Account *acct;
|
||||
AccountGroup *ag;
|
||||
char *name;
|
||||
|
||||
sx->freq = xaccFreqSpecMalloc();
|
||||
|
||||
xaccGUIDNew( &sx->guid );
|
||||
xaccStoreEntity( sx, &sx->guid, GNC_ID_SCHEDXACTION );
|
||||
g_date_clear( &sx->last_date, 1 );
|
||||
g_date_clear( &sx->start_date, 1 );
|
||||
g_date_clear( &sx->end_date, 1 );
|
||||
|
||||
sx->num_occurances_total = -1;
|
||||
sx->kvp_data = kvp_frame_new();
|
||||
sx->manual = FALSE;
|
||||
|
||||
sx->templateSplits = NULL;
|
||||
// create a new template account for our splits...
|
||||
acct = xaccMallocAccount();
|
||||
name = guid_to_string( &sx->guid );
|
||||
xaccAccountSetName( acct, name );
|
||||
xaccAccountSetCurrency( acct,
|
||||
gnc_commodity_new( "template", "template", "template", "template", 1 ) );
|
||||
// FIXME: g_free?
|
||||
// FIXME: leaks
|
||||
// g_free( name );
|
||||
xaccAccountSetType( acct, BANK );
|
||||
ag = gnc_book_get_template_group( book );
|
||||
xaccGroupInsertAccount( ag, acct );
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionFree( SchedXaction *sx )
|
||||
{
|
||||
if ( sx == NULL ) return;
|
||||
|
||||
xaccFreqSpecFree( sx->freq );
|
||||
gnc_engine_generate_event( &sx->guid, GNC_EVENT_DESTROY );
|
||||
xaccRemoveEntity( &sx->guid );
|
||||
|
||||
g_list_foreach( sx->templateSplits,
|
||||
transactionListMapDelete,
|
||||
NULL );
|
||||
g_list_free( sx->templateSplits );
|
||||
if ( sx->name )
|
||||
g_free( sx->name );
|
||||
g_free( sx );
|
||||
|
||||
// FIXME: clean up our template account...
|
||||
}
|
||||
|
||||
void
|
||||
transactionListMapDelete( gpointer data, gpointer user_data )
|
||||
{
|
||||
Transaction *t = (Transaction*)data;
|
||||
xaccTransBeginEdit( t );
|
||||
xaccTransDestroy( t );
|
||||
xaccTransCommitEdit( t );
|
||||
}
|
||||
|
||||
FreqSpec *
|
||||
xaccSchedXactionGetFreqSpec( SchedXaction *sx )
|
||||
{
|
||||
return sx->freq;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetFreqSpec( SchedXaction *sx, FreqSpec *fs )
|
||||
{
|
||||
g_return_if_fail( fs );
|
||||
|
||||
xaccFreqSpecFree( sx->freq );
|
||||
sx->freq = fs;
|
||||
}
|
||||
|
||||
gchar *
|
||||
xaccSchedXactionGetName( SchedXaction *sx )
|
||||
{
|
||||
return sx->name;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetName( SchedXaction *sx, const gchar *newName )
|
||||
{
|
||||
GString *gstr;
|
||||
g_return_if_fail( newName != NULL );
|
||||
if ( sx->name != NULL ) {
|
||||
g_free( sx->name );
|
||||
}
|
||||
gstr = g_string_new( newName );
|
||||
sx->name = gstr->str;
|
||||
g_string_free( gstr, FALSE );
|
||||
}
|
||||
|
||||
GDate*
|
||||
xaccSchedXactionGetStartDate( SchedXaction *sx )
|
||||
{
|
||||
return &sx->start_date;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetStartDate( SchedXaction *sx, GDate* newStart )
|
||||
{
|
||||
sx->start_date = *newStart;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccSchedXactionHasEndDate( SchedXaction *sx )
|
||||
{
|
||||
return g_date_valid( &sx->end_date );
|
||||
}
|
||||
|
||||
GDate*
|
||||
xaccSchedXactionGetEndDate( SchedXaction *sx )
|
||||
{
|
||||
return &sx->end_date;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetEndDate( SchedXaction *sx, GDate *newEnd )
|
||||
{
|
||||
if ( g_date_valid( newEnd ) ) {
|
||||
if ( g_date_compare( newEnd, &sx->start_date ) < 0 ) {
|
||||
// FIXME:error
|
||||
// error( "New end date before start date" );
|
||||
}
|
||||
}
|
||||
sx->end_date = *newEnd;
|
||||
}
|
||||
|
||||
GDate*
|
||||
xaccSchedXactionGetLastOccurDate( SchedXaction *sx )
|
||||
{
|
||||
return &sx->last_date;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetLastOccurDate( SchedXaction *sx, GDate* newLastOccur )
|
||||
{
|
||||
sx->last_date = *newLastOccur;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccSchedXactionHasOccurDef( SchedXaction *sx )
|
||||
{
|
||||
return ( xaccSchedXactionGetNumOccur( sx ) != 0 );
|
||||
}
|
||||
|
||||
gint
|
||||
xaccSchedXactionGetNumOccur( SchedXaction *sx )
|
||||
{
|
||||
return sx->num_occurances_total;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetNumOccur( SchedXaction *sx, gint newNum )
|
||||
{
|
||||
sx->num_occurances_remain = sx->num_occurances_total = newNum;
|
||||
|
||||
}
|
||||
|
||||
gint
|
||||
xaccSchedXactionGetRemOccur( SchedXaction *sx )
|
||||
{
|
||||
return sx->num_occurances_remain;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetRemOccur( SchedXaction *sx,
|
||||
gint numRemain )
|
||||
{
|
||||
/* FIXME This condition can be tightened up */
|
||||
if ( numRemain > sx->num_occurances_total ) {
|
||||
// FIXME:error
|
||||
// error( "more remaining occurances than total" );
|
||||
}
|
||||
sx->num_occurances_remain = numRemain;
|
||||
}
|
||||
|
||||
kvp_frame*
|
||||
xaccSchedXactionGetSlots( SchedXaction *sx )
|
||||
{
|
||||
return sx->kvp_data;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetSlots( SchedXaction *sx, kvp_frame *frm )
|
||||
{
|
||||
sx->kvp_data = frm;
|
||||
}
|
||||
|
||||
const GUID*
|
||||
xaccSchedXactionGetGUID( SchedXaction *sx )
|
||||
{
|
||||
return &sx->guid;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetGUID( SchedXaction *sx, GUID g )
|
||||
{
|
||||
sx->guid = g;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetManual( SchedXaction *sx, gboolean newManual )
|
||||
{
|
||||
sx->manual = newManual;
|
||||
}
|
||||
|
||||
int
|
||||
xaccSchedXactionGetManual( SchedXaction *sx )
|
||||
{
|
||||
return sx->manual;
|
||||
}
|
||||
|
||||
GDate
|
||||
xaccSchedXactionGetNextInstance( SchedXaction *sx )
|
||||
{
|
||||
GDate last_occur, next_occur;
|
||||
|
||||
if ( g_date_valid( &sx->last_date ) ) {
|
||||
last_occur = sx->last_date;
|
||||
} else {
|
||||
if ( g_date_valid( &sx->start_date ) ) {
|
||||
last_occur = sx->start_date;
|
||||
} else {
|
||||
g_date_set_time( &last_occur, time(NULL) );
|
||||
}
|
||||
}
|
||||
xaccFreqSpecGetNextInstance( sx->freq, &last_occur, &next_occur );
|
||||
return next_occur;
|
||||
}
|
||||
|
||||
GDate xaccSchedXactionGetInstanceAfter( SchedXaction *sx, GDate *date )
|
||||
{
|
||||
GDate next_occur;
|
||||
xaccFreqSpecGetNextInstance( sx->freq, date, &next_occur );
|
||||
return next_occur;
|
||||
}
|
||||
|
||||
GList *
|
||||
xaccSchedXactionGetSplits( SchedXaction *sx )
|
||||
{
|
||||
g_return_val_if_fail( sx, NULL );
|
||||
return sx->templateSplits;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSchedXactionSetSplits( SchedXaction *sx, GList *newSplits )
|
||||
{
|
||||
g_return_if_fail( sx );
|
||||
sx->templateSplits = newSplits;
|
||||
}
|
||||
170
src/engine/SchedXaction.h
Normal file
170
src/engine/SchedXaction.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/********************************************************************\
|
||||
* SchedXaction.h -- Scheduled Transaction *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef XACC_SCHEDXACTION_H
|
||||
#define XACC_SCHEDXACTION_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <glib.h>
|
||||
#include "GNCId.h"
|
||||
#include "FreqSpec.h"
|
||||
#include "date.h"
|
||||
#include "kvp_frame.h"
|
||||
#include "gnc-book.h"
|
||||
|
||||
/**
|
||||
* A single scheduled transaction.
|
||||
*
|
||||
* Scheduled transactions have a list of transactions, and a frequency
|
||||
* [and associated date anchors] with which they are scheduled.
|
||||
*
|
||||
* Things that make sense to have in a template transaction:
|
||||
* [not] Date [though eventually some/multiple template transactions
|
||||
* might have relative dates].
|
||||
* Memo
|
||||
* Account
|
||||
* Funds In/Out... or an expr involving 'amt' [A, x, y, a?] for
|
||||
* variable expenses.
|
||||
*
|
||||
* Template transactions are instantiated by:
|
||||
* . copying the fields of the template
|
||||
* . setting the date to the calculated "due" date.
|
||||
*
|
||||
* We should be able to use the GeneralLedger [or, yet-another-subtype
|
||||
* of the internal ledger] for this editing.
|
||||
**/
|
||||
typedef struct gncp_SchedXaction {
|
||||
gchar *name;
|
||||
|
||||
FreqSpec *freq;
|
||||
|
||||
GDate last_date;
|
||||
|
||||
GDate start_date;
|
||||
// if end_date is invalid, then no end.
|
||||
GDate end_date;
|
||||
|
||||
// if num_occurances_total == 0, then no limit
|
||||
gint num_occurances_total;
|
||||
// reminaing occurances are as-of the 'last_date'.
|
||||
gint num_occurances_remain;
|
||||
|
||||
// If true, confirmation is required.
|
||||
// If false, then this can be created when due without
|
||||
// intervention.
|
||||
gboolean manual;
|
||||
|
||||
GList *templateSplits;
|
||||
|
||||
GUID guid;
|
||||
kvp_frame *kvp_data;
|
||||
} SchedXaction;
|
||||
|
||||
/**
|
||||
* Creates and initializes a scheduled transaction.
|
||||
**/
|
||||
SchedXaction *xaccSchedXactionMalloc( GNCBook *book );
|
||||
/**
|
||||
* Initially created with a null name, the default frequency, a
|
||||
* start-date of today, no end date, no counted occurances, no
|
||||
* templates transactions, and null kvp data.
|
||||
**/
|
||||
void xaccSchedXactionInit( SchedXaction *sx, GNCBook *book );
|
||||
/**
|
||||
* Cleans up and frees a SchedXaction and it's associated data.
|
||||
**/
|
||||
void xaccSchedXactionFree( SchedXaction *sx );
|
||||
|
||||
FreqSpec *xaccSchedXactionGetFreqSpec( SchedXaction *sx );
|
||||
/**
|
||||
* The FreqSpec is given to the SchedXaction for mem mgmt; it should
|
||||
* not be freed by the external code.
|
||||
**/
|
||||
void xaccSchedXactionSetFreqSpec( SchedXaction *sx, FreqSpec *fs );
|
||||
|
||||
gchar *xaccSchedXactionGetName( SchedXaction *sx );
|
||||
/**
|
||||
* A copy of the name is made.
|
||||
**/
|
||||
void xaccSchedXactionSetName( SchedXaction *sx, const gchar *newName );
|
||||
|
||||
GDate* xaccSchedXactionGetStartDate( SchedXaction *sx );
|
||||
void xaccSchedXactionSetStartDate( SchedXaction *sx, GDate* newStart );
|
||||
|
||||
int xaccSchedXactionHasEndDate( SchedXaction *sx );
|
||||
/**
|
||||
* Returns invalid date when there is no end-date specified.
|
||||
**/
|
||||
GDate* xaccSchedXactionGetEndDate( SchedXaction *sx );
|
||||
void xaccSchedXactionSetEndDate( SchedXaction *sx, GDate* newEnd );
|
||||
|
||||
GDate* xaccSchedXactionGetLastOccurDate( SchedXaction *sx );
|
||||
void xaccSchedXactionSetLastOccurDate( SchedXaction *sx, GDate* newLastOccur );
|
||||
|
||||
/**
|
||||
* Returns true if the scheduled transaction has a defined number of
|
||||
* occurances, false if not.
|
||||
**/
|
||||
gboolean xaccSchedXactionHasOccurDef( SchedXaction *sx );
|
||||
gint xaccSchedXactionGetNumOccur( SchedXaction *sx );
|
||||
void xaccSchedXactionSetNumOccur( SchedXaction *sx, gint numNum );
|
||||
gint xaccSchedXactionGetRemOccur( SchedXaction *sx );
|
||||
void xaccSchedXactionSetRemOccur( SchedXaction *sx, gint numRemain );
|
||||
|
||||
GList *xaccSchedXactionGetSplits( SchedXaction *sx );
|
||||
void xaccSchedXactionSetSplits( SchedXaction *sx, GList *newSplits );
|
||||
|
||||
gboolean xaccSchedXactionGetManual( SchedXaction *sx );
|
||||
void xaccSchedXactionSetManual( SchedXaction *sx, gboolean newManual );
|
||||
|
||||
#if 0
|
||||
#error vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
GList *xaccSchedXactionGetXactions( SchedXaction *sx );
|
||||
void xaccSchedXactionClearXactions( SchedXaction *sx );
|
||||
void xaccSchedXactionAddXaction( SchedXaction *sx,
|
||||
Transaction *t );
|
||||
#error ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
#endif // 0
|
||||
|
||||
kvp_frame *xaccSchedXactionGetSlots( SchedXaction *sx );
|
||||
/**
|
||||
* Sets the SX kvp data to the given kvp_frame.
|
||||
* NOTE: This is not copied, but set directly.
|
||||
**/
|
||||
void xaccSchedXactionSetSlots( SchedXaction *sx,
|
||||
kvp_frame *frm );
|
||||
|
||||
const GUID *xaccSchedXactionGetGUID( SchedXaction *sx );
|
||||
void xaccSchedXactionSetGUID( SchedXaction *sx, GUID g );
|
||||
|
||||
/**
|
||||
* Returns the next occurance of a scheduled transaction. If the
|
||||
* transaction hasn't occured, then it's based off the start date.
|
||||
* Otherwise, it's based off the last-occurance date.
|
||||
**/
|
||||
GDate xaccSchedXactionGetNextInstance( SchedXaction *sx );
|
||||
GDate xaccSchedXactionGetInstanceAfter( SchedXaction *sx, GDate *date );
|
||||
|
||||
#endif /* XACC_SCHEDXACTION_H */
|
||||
@@ -689,5 +689,13 @@ gnc_timezone (struct tm *tm)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
timespecFromTime_t( Timespec *ts, time_t t )
|
||||
{
|
||||
ts->tv_sec = t;
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
/********************** END OF FILE *********************************\
|
||||
\********************************************************************/
|
||||
|
||||
@@ -122,6 +122,11 @@ void printDateSecs (char * buff, time_t secs);
|
||||
char * xaccPrintDateSecs (time_t secs);
|
||||
const char * gnc_print_date(Timespec ts);
|
||||
|
||||
/**
|
||||
* Turns a time_t into a Timespec
|
||||
**/
|
||||
void timespecFromTime_t( Timespec *ts, time_t t );
|
||||
|
||||
/**
|
||||
* scanDate
|
||||
* Convert a string into day / month / year integers according to
|
||||
|
||||
@@ -326,6 +326,25 @@ gnc_account_end_handler(gpointer data_for_children,
|
||||
return successful;
|
||||
}
|
||||
|
||||
Account*
|
||||
dom_tree_to_account( xmlNodePtr node )
|
||||
{
|
||||
Account *accToRet;
|
||||
gboolean successful;
|
||||
|
||||
accToRet = xaccMallocAccount();
|
||||
successful = dom_tree_generic_parse( node, account_handlers_v2, accToRet );
|
||||
xaccAccountCommitEdit( accToRet );
|
||||
|
||||
if ( !successful ) {
|
||||
xaccFreeAccount( accToRet );
|
||||
accToRet = NULL;
|
||||
}
|
||||
// jsled_FIXME? See note above.
|
||||
xaccAccountBeginEdit( accToRet );
|
||||
return accToRet;
|
||||
}
|
||||
|
||||
sixtp*
|
||||
gnc_account_sixtp_parser_create(void)
|
||||
{
|
||||
|
||||
@@ -69,6 +69,8 @@ struct _gnc_book
|
||||
{
|
||||
AccountGroup *topgroup;
|
||||
GNCPriceDB *pricedb;
|
||||
GList *sched_xactions;
|
||||
AccountGroup *template_group;
|
||||
|
||||
/* the requested book id, in the form or a URI, such as
|
||||
* file:/some/where, or sql:server.host.com:555
|
||||
@@ -157,13 +159,21 @@ gnc_book_pop_error (GNCBook * book)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
const char *TEMPLATE_ACCOUNT_NAME = "__account for template transactions__";
|
||||
|
||||
static void
|
||||
gnc_book_init (GNCBook *book)
|
||||
{
|
||||
Account *template_acct;
|
||||
|
||||
if(!book) return;
|
||||
|
||||
book->topgroup = xaccMallocAccountGroup();
|
||||
book->pricedb = gnc_pricedb_create();
|
||||
|
||||
book->sched_xactions = NULL;
|
||||
book->template_group = xaccMallocAccountGroup();
|
||||
|
||||
book->book_id = NULL;
|
||||
gnc_book_clear_error (book);
|
||||
book->fullpath = NULL;
|
||||
@@ -241,6 +251,34 @@ gnc_book_set_pricedb(GNCBook *book, GNCPriceDB *db)
|
||||
book->pricedb = db;
|
||||
}
|
||||
|
||||
GList *
|
||||
gnc_book_get_schedxactions( GNCBook *book )
|
||||
{
|
||||
if ( book == NULL ) return NULL;
|
||||
return book->sched_xactions;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_book_set_schedxactions( GNCBook *book, GList *newList )
|
||||
{
|
||||
if ( book == NULL ) return;
|
||||
book->sched_xactions = newList;
|
||||
}
|
||||
|
||||
AccountGroup *
|
||||
gnc_book_get_template_group( GNCBook *book )
|
||||
{
|
||||
if ( book == NULL ) return NULL;
|
||||
return book->template_group;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_book_set_template_group( GNCBook *book, AccountGroup *templateGroup )
|
||||
{
|
||||
if ( book == NULL ) return;
|
||||
book->template_group = templateGroup;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
Backend *
|
||||
|
||||
@@ -132,6 +132,15 @@ guint gnc_book_count_transactions(GNCBook *book);
|
||||
*/
|
||||
gnc_commodity_table* gnc_book_get_commodity_table(GNCBook *book);
|
||||
|
||||
/**
|
||||
* Returns the list of scheduled transactions.
|
||||
**/
|
||||
GList * gnc_book_get_schedxactions( GNCBook *book );
|
||||
void gnc_book_set_schedxactions( GNCBook *book, GList *newList );
|
||||
|
||||
AccountGroup *gnc_book_get_template_group( GNCBook *book );
|
||||
void gnc_book_set_template_group( GNCBook *book, AccountGroup *templateGroup );
|
||||
|
||||
/* The gnc_book_get_file_path() routine returns the fully-qualified file
|
||||
* path for the book. That is, if a relative or partial filename
|
||||
* was for the book, then it had to have been fully resolved to
|
||||
|
||||
@@ -61,7 +61,8 @@ typedef enum
|
||||
MOD_EVENT = 13,
|
||||
MOD_TXN = 14,
|
||||
MOD_KVP = 15,
|
||||
MOD_LAST = 15
|
||||
MOD_SX = 16,
|
||||
MOD_LAST = 16
|
||||
} gncModuleType;
|
||||
|
||||
typedef enum
|
||||
|
||||
589
src/engine/gnc-freqspec-xml-v2.c
Normal file
589
src/engine/gnc-freqspec-xml-v2.c
Normal file
@@ -0,0 +1,589 @@
|
||||
/********************************************************************
|
||||
* gnc-freqspec-xml-v2.c -- xml routines for FreqSpecs *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
*******************************************************************/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-xml-helper.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#include "sixtp.h"
|
||||
#include "sixtp-utils.h"
|
||||
#include "sixtp-parsers.h"
|
||||
#include "sixtp-utils.h"
|
||||
#include "sixtp-xml-write-utils.h"
|
||||
#include "sixtp-dom-parsers.h"
|
||||
#include "sixtp-dom-generators.h"
|
||||
|
||||
#include "gnc-xml.h"
|
||||
|
||||
#include "io-gncxml-v2.h"
|
||||
|
||||
#include "sixtp-dom-parsers.h"
|
||||
#include "SchedXaction.h"
|
||||
#include "FreqSpecP.h"
|
||||
|
||||
/**
|
||||
* The XML output should look something like:
|
||||
* <freqspec>
|
||||
* <fs:monthly>
|
||||
* <fs:interval>2</fs:interval>
|
||||
* <fs:offset>1</fs:offset>
|
||||
* <fs:day>21</fs:day>
|
||||
* </fs:monthly>
|
||||
* <fs:id>...</fs:id>
|
||||
* </freqspec>
|
||||
*
|
||||
* <freqspec>
|
||||
*
|
||||
* <fs:composite>
|
||||
* <freqspec>
|
||||
* <fs:weekly>
|
||||
* <fs:interval>2</fs:interval>
|
||||
* <fs:offset>3</fs:offset>
|
||||
* </fs:weekly>
|
||||
* </freqspec>
|
||||
* <freqspec>
|
||||
* <fs:weekly>
|
||||
* <fs:interval>2</fs:interval>
|
||||
* <fs:offset>12</fs:offset>
|
||||
* </fs:weekly>
|
||||
* </freqspec>
|
||||
* </fs:composite>
|
||||
* <fs:id>...</fs:id>
|
||||
* </freqspec>
|
||||
*
|
||||
**/
|
||||
|
||||
const gchar *freqspec_version_string = "1.0.0";
|
||||
|
||||
struct freqTypeTuple {
|
||||
char *str;
|
||||
FreqType ft;
|
||||
};
|
||||
|
||||
struct freqTypeTuple freqTypeStrs[] = {
|
||||
{ "once", ONCE },
|
||||
{ "daily", DAILY },
|
||||
{ "weekly", WEEKLY },
|
||||
{ "monthly", MONTHLY },
|
||||
{ "month_relative", MONTH_RELATIVE },
|
||||
{ "composite", COMPOSITE },
|
||||
{ NULL, -1 },
|
||||
};
|
||||
|
||||
struct uiFreqTypeTuple {
|
||||
char *str;
|
||||
UIFreqType uift;
|
||||
};
|
||||
|
||||
struct uiFreqTypeTuple uiFreqTypeStrs[] = {
|
||||
{ "none", UIFREQ_NONE },
|
||||
{ "once", UIFREQ_ONCE },
|
||||
{ "daily", UIFREQ_DAILY },
|
||||
{ "daily_mf", UIFREQ_DAILY_MF },
|
||||
{ "weekly", UIFREQ_WEEKLY },
|
||||
{ "bi_weekly", UIFREQ_BI_WEEKLY },
|
||||
{ "semi_monthly", UIFREQ_SEMI_MONTHLY },
|
||||
{ "monthly", UIFREQ_MONTHLY },
|
||||
{ "quarterly", UIFREQ_QUARTERLY },
|
||||
{ "tri_anually", UIFREQ_TRI_ANUALLY },
|
||||
{ "semi_yearly", UIFREQ_SEMI_YEARLY },
|
||||
{ "yearly", UIFREQ_YEARLY },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct passed around as user-data when parsing the FreqSpec.
|
||||
**/
|
||||
typedef struct _freqSpecParseData {
|
||||
FreqSpec *fs; // FreqSpec we're parsing into.
|
||||
// fields used in the union of unions... :)
|
||||
GDate once_day; // once
|
||||
gint64 interval; // all [except once]
|
||||
gint64 offset; // all [except once]
|
||||
gint64 day; // monthly or month-relative
|
||||
gint64 occurrence; // month-relative
|
||||
GList *list; // composite
|
||||
} fsParseData;
|
||||
|
||||
void
|
||||
_fspd_init( fsParseData *fspd )
|
||||
{
|
||||
fspd->fs = NULL;
|
||||
fspd->list = NULL;
|
||||
fspd->interval
|
||||
= fspd->offset
|
||||
= fspd->day
|
||||
= fspd->occurrence
|
||||
= 0;
|
||||
g_date_clear( &fspd->once_day, 1 );
|
||||
}
|
||||
|
||||
FreqSpec *dom_tree_to_freqSpec(xmlNodePtr node);
|
||||
|
||||
xmlNodePtr
|
||||
gnc_freqSpec_dom_tree_create( FreqSpec *fs )
|
||||
{
|
||||
xmlNodePtr ret;
|
||||
xmlNodePtr dateAnchorTmp;
|
||||
xmlNodePtr xmlSub;
|
||||
GString *tmpStr;
|
||||
int i;
|
||||
|
||||
ret = xmlNewNode( NULL, "gnc:freqspec" );
|
||||
xmlSetProp( ret, "version", freqspec_version_string );
|
||||
|
||||
xmlAddChild( ret, guid_to_dom_tree( "fs:id", &fs->guid ) );
|
||||
|
||||
xmlSub = text_to_dom_tree( "fs:ui_type",
|
||||
uiFreqTypeStrs[ xaccFreqSpecGetUIType(fs) ].str );
|
||||
xmlAddChild( ret, xmlSub );
|
||||
|
||||
switch( fs->type ) {
|
||||
case ONCE: {
|
||||
xmlSub = xmlNewNode( NULL, "fs:once" );
|
||||
xmlAddChild( xmlSub,
|
||||
gdate_to_dom_tree( "fs:date",
|
||||
&fs->s.once.date ) );
|
||||
xmlAddChild( ret, xmlSub );
|
||||
} break;
|
||||
|
||||
case DAILY: {
|
||||
xmlSub = xmlNewNode( NULL, "fs:daily" );
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:interval",
|
||||
fs->s.daily.interval_days )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:offset",
|
||||
fs->s.daily.offset_from_epoch )
|
||||
);
|
||||
xmlAddChild( ret, xmlSub );
|
||||
} break;
|
||||
|
||||
case WEEKLY: {
|
||||
xmlSub = xmlNewNode( NULL, "fs:weekly" );
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:interval",
|
||||
fs->s.weekly.interval_weeks )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:offset",
|
||||
fs->s.weekly.offset_from_epoch )
|
||||
);
|
||||
xmlAddChild( ret, xmlSub );
|
||||
} break;
|
||||
|
||||
case MONTHLY: {
|
||||
xmlSub = xmlNewNode( NULL, "fs:monthly" );
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:interval",
|
||||
fs->s.monthly.interval_months )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:offset",
|
||||
fs->s.monthly.offset_from_epoch )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:day",
|
||||
fs->s.monthly.day_of_month )
|
||||
);
|
||||
xmlAddChild( ret, xmlSub );
|
||||
} break;
|
||||
|
||||
case MONTH_RELATIVE: {
|
||||
xmlSub = xmlNewNode( NULL, "fs:month_relative" );
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:interval",
|
||||
fs->s.month_relative.interval_months )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:offset",
|
||||
fs->s.month_relative.offset_from_epoch )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:weekday",
|
||||
fs->s.month_relative.weekday )
|
||||
);
|
||||
xmlAddChild( xmlSub,
|
||||
guint_to_dom_tree(
|
||||
"fs:occurrence",
|
||||
fs->s.month_relative.occurrence )
|
||||
);
|
||||
xmlAddChild( ret, xmlSub );
|
||||
} break;
|
||||
|
||||
case COMPOSITE: {
|
||||
GList *subelts;
|
||||
xmlNodePtr xmlComposites;
|
||||
xmlComposites = xmlNewNode( NULL, "fs:composite" );
|
||||
subelts = fs->s.composites.subSpecs;
|
||||
while( subelts ) {
|
||||
xmlAddChild( xmlComposites,
|
||||
gnc_freqSpec_dom_tree_create(
|
||||
subelts->data ) );
|
||||
subelts = subelts->next;
|
||||
}
|
||||
xmlAddChild( ret, xmlComposites );
|
||||
} break;
|
||||
|
||||
case INVALID:
|
||||
default:
|
||||
g_return_val_if_fail( FALSE, NULL );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gnc_fs_handler( xmlNodePtr node, gpointer d )
|
||||
{
|
||||
// we ignore the wrapper... we were just called at the wrong
|
||||
// level.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_uift_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
int i;
|
||||
char *nodeTxt;
|
||||
char *tmp;
|
||||
|
||||
nodeTxt = dom_tree_to_text( node );
|
||||
|
||||
g_return_val_if_fail( nodeTxt, FALSE );
|
||||
for ( i=0; (tmp = uiFreqTypeStrs[i].str) != NULL; i++ ) {
|
||||
if ( safe_strcmp( nodeTxt, tmp ) == 0 ) {
|
||||
xaccFreqSpecSetUIType( fspd->fs, uiFreqTypeStrs[i].uift );
|
||||
g_free( nodeTxt );
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
g_free( nodeTxt );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_date_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
GDate *foo;
|
||||
foo = dom_tree_to_gdate( node );
|
||||
if ( foo == NULL )
|
||||
return FALSE;
|
||||
fspd->once_day = *foo;
|
||||
g_date_free( foo );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_interval_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean ret;
|
||||
gint64 foo;
|
||||
|
||||
ret = dom_tree_to_integer( node, &foo );
|
||||
if ( ! ret ) {
|
||||
return ret;
|
||||
}
|
||||
fspd->interval = foo;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_offset_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean ret;
|
||||
gint64 foo;
|
||||
|
||||
ret = dom_tree_to_integer( node, &foo );
|
||||
if ( ! ret )
|
||||
return ret;
|
||||
fspd->offset = foo;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_day_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean ret;
|
||||
gint64 foo;
|
||||
|
||||
ret = dom_tree_to_integer( node, &foo );
|
||||
if ( ! ret )
|
||||
return ret;
|
||||
fspd->day = foo;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_weekday_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean ret;
|
||||
gint64 foo;
|
||||
ret = dom_tree_to_integer( node, &foo );
|
||||
if ( !ret )
|
||||
return ret;
|
||||
fspd->day = foo;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_occurrence_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean ret;
|
||||
gint64 foo;
|
||||
ret = dom_tree_to_integer( node, &foo );
|
||||
if ( !ret )
|
||||
return ret;
|
||||
fspd->occurrence = foo;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_subelement_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
FreqSpec *fs;
|
||||
gboolean successful;
|
||||
fs = dom_tree_to_freqSpec( node );
|
||||
if ( fs == NULL )
|
||||
return FALSE;
|
||||
fspd->list = g_list_append( fspd->list, fs );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct dom_tree_handler fs_union_dom_handlers[] = {
|
||||
{ "fs:date", fs_date_handler, 0, 0 },
|
||||
{ "fs:interval", fs_interval_handler, 0, 0 },
|
||||
{ "fs:offset", fs_offset_handler, 0, 0 },
|
||||
{ "fs:day", fs_day_handler, 0, 0 },
|
||||
{ "fs:weekday", fs_weekday_handler, 0, 0 },
|
||||
{ "fs:occurrence", fs_occurrence_handler, 0, 0 },
|
||||
{ "gnc:freqspec", fs_subelement_handler, 0, 0 },
|
||||
{ NULL, NULL, 0, 0 },
|
||||
};
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_once_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = ONCE;
|
||||
fspd->fs->s.once.date = fspd->once_day;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_daily_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = DAILY;
|
||||
fspd->fs->s.daily.interval_days = fspd->interval;
|
||||
fspd->fs->s.daily.offset_from_epoch = fspd->offset;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_weekly_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = WEEKLY;
|
||||
fspd->fs->s.weekly.interval_weeks = fspd->interval;
|
||||
fspd->fs->s.weekly.offset_from_epoch = fspd->offset;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_monthly_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = MONTHLY;
|
||||
fspd->fs->s.monthly.interval_months = fspd->interval;
|
||||
fspd->fs->s.monthly.offset_from_epoch = fspd->offset;
|
||||
fspd->fs->s.monthly.day_of_month = fspd->day;
|
||||
return successful;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_month_relative_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = MONTH_RELATIVE;
|
||||
fspd->fs->s.month_relative.interval_months = fspd->interval;
|
||||
fspd->fs->s.month_relative.offset_from_epoch = fspd->offset;
|
||||
fspd->fs->s.month_relative.weekday = fspd->day;
|
||||
fspd->fs->s.month_relative.occurrence = fspd->occurrence;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_guid_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
GUID *guid;
|
||||
guid = dom_tree_to_guid( node );
|
||||
fspd->fs->guid = *guid;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
fs_composite_handler( xmlNodePtr node, fsParseData *fspd )
|
||||
{
|
||||
gboolean successful;
|
||||
successful = dom_tree_generic_parse( node,
|
||||
fs_union_dom_handlers,
|
||||
fspd );
|
||||
if ( !successful )
|
||||
return FALSE;
|
||||
fspd->fs->type = COMPOSITE;
|
||||
fspd->fs->s.composites.subSpecs = fspd->list;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct dom_tree_handler fs_dom_handlers[] = {
|
||||
{ "gnc:freqspec", gnc_fs_handler, 0, 0 },
|
||||
{ "fs:ui_type", fs_uift_handler, 1, 0 },
|
||||
{ "fs:id", fs_guid_handler, 1, 0 },
|
||||
{ "fs:once", fs_once_handler, 0, 0 },
|
||||
{ "fs:daily", fs_daily_handler, 0, 0 },
|
||||
{ "fs:weekly", fs_weekly_handler, 0, 0 },
|
||||
{ "fs:monthly", fs_monthly_handler, 0, 0 },
|
||||
{ "fs:month_relative", fs_month_relative_handler, 0, 0 },
|
||||
{ "fs:composite", fs_composite_handler, 0, 0 },
|
||||
{ NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static
|
||||
gboolean
|
||||
gnc_freqSpec_end_handler(gpointer data_for_children,
|
||||
GSList* data_from_children, GSList* sibling_data,
|
||||
gpointer parent_data, gpointer global_data,
|
||||
gpointer *result, const gchar *tag)
|
||||
{
|
||||
fsParseData fspd;
|
||||
gboolean successful = FALSE;
|
||||
xmlNodePtr aChild;
|
||||
xmlNodePtr tree = (xmlNodePtr)data_for_children;
|
||||
sixtp_gdv2 *globaldata = (sixtp_gdv2*)global_data;
|
||||
|
||||
_fspd_init( &fspd );
|
||||
|
||||
// this won't actually get invoked [FreqSpecs aren't top-level
|
||||
// elements]; see dom_tree_to_freqSpec(), below.
|
||||
if ( parent_data )
|
||||
return TRUE;
|
||||
|
||||
if ( !tag )
|
||||
return TRUE;
|
||||
|
||||
g_return_val_if_fail( tree, FALSE );
|
||||
|
||||
fspd.fs = xaccFreqSpecMalloc();
|
||||
successful = dom_tree_generic_parse( tree, fs_dom_handlers, &fspd );
|
||||
if (!successful) {
|
||||
xmlElemDump( stdout, NULL, tree );
|
||||
xaccFreqSpecFree( fspd.fs );
|
||||
}
|
||||
|
||||
xmlFreeNode(tree);
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
sixtp*
|
||||
gnc_freqSpec_sixtp_parser_create(void)
|
||||
{
|
||||
return sixtp_dom_parser_new( gnc_freqSpec_end_handler, NULL, NULL );
|
||||
}
|
||||
|
||||
FreqSpec*
|
||||
dom_tree_to_freqSpec(xmlNodePtr node)
|
||||
{
|
||||
gboolean successful;
|
||||
fsParseData fspd;
|
||||
|
||||
_fspd_init( &fspd );
|
||||
|
||||
fspd.fs = xaccFreqSpecMalloc();
|
||||
successful = dom_tree_generic_parse( node, fs_dom_handlers, &fspd );
|
||||
if ( !successful ) {
|
||||
xaccFreqSpecFree( fspd.fs );
|
||||
fspd.fs = NULL;
|
||||
}
|
||||
return fspd.fs;
|
||||
}
|
||||
443
src/engine/gnc-schedxaction-xml-v2.c
Normal file
443
src/engine/gnc-schedxaction-xml-v2.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/********************************************************************
|
||||
* gnc-schedxactions-xml-v2.c -- xml routines for transactions *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
*******************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gnc-xml-helper.h"
|
||||
#include "gnc-engine-util.h"
|
||||
|
||||
#include "sixtp.h"
|
||||
#include "sixtp-utils.h"
|
||||
#include "sixtp-xml-write-utils.h"
|
||||
#include "sixtp-parsers.h"
|
||||
#include "sixtp-utils.h"
|
||||
#include "sixtp-dom-parsers.h"
|
||||
#include "sixtp-dom-generators.h"
|
||||
|
||||
#include "gnc-xml.h"
|
||||
|
||||
#include "io-gncxml-v2.h"
|
||||
#include "io-gncxml-gen.h"
|
||||
|
||||
#include "sixtp-dom-parsers.h"
|
||||
#include "SchedXaction.h"
|
||||
|
||||
/**
|
||||
* The XML output should look something like:
|
||||
* <gnc:count-data cd:type="schedXaction">XXX</gnc:count-data>
|
||||
* ...
|
||||
* <gnc:schedxaction version="1.0.0">
|
||||
* <sx:id type="guid">...</sx:id>
|
||||
* <sx:name>Rent</sx:name>
|
||||
* <sx:manual-conf>f</sx:manual-conf>
|
||||
* <sx:lastOccur>
|
||||
* <gdate>2001-02-28</gdate>
|
||||
* </sx:lastOccur>
|
||||
* <sx:start>
|
||||
* <gdate>2000-12-31</gdate>
|
||||
* </sx:start>
|
||||
* <!-- no end -->
|
||||
* <sx:freq>
|
||||
* <!-- freq spec tree -->
|
||||
* </sx:freq>
|
||||
* </gnc:schedxaction>
|
||||
* <gnc:schedxaction version="1.0.0">
|
||||
* <sx:id type="guid">...</sx:id>
|
||||
* <sx:name>Loan 1</sx:name>
|
||||
* <sx:manual-conf>f</sx:manual-conf>
|
||||
* <sx:start>
|
||||
* <gdate>2000-12-31</gdate>
|
||||
* </sx:start>
|
||||
* <sx:end type="date">
|
||||
* <gdate>2004-03-20</gdate>
|
||||
* </sx:end>
|
||||
* <sx:freq>
|
||||
* <!-- freqspec tree -->
|
||||
* </sx:freq>
|
||||
* </gnc:schedxaction>
|
||||
* <gnc:schedxaction version="1.0.0">
|
||||
* <sx:id type="guid">...</sx:id>
|
||||
* <sx:name>Loan 2</sx:name>
|
||||
* <sx:manual-conf>f</sx:manual-conf>
|
||||
* <sx:start>
|
||||
* <gdate>2000-12-31</gdate>
|
||||
* </sx:start>
|
||||
* <sx:end type="num_occur">
|
||||
* <sx:num>42</sx:num>
|
||||
* </sx:end>
|
||||
* <sx:freq>
|
||||
* <!-- freqspec tree -->
|
||||
* </sx:freq>
|
||||
* </gnc:schedxaction>
|
||||
*
|
||||
* et-cetera...
|
||||
* bleh.
|
||||
**/
|
||||
|
||||
const gchar *schedxaction_version_string = "1.0.0";
|
||||
|
||||
xmlNodePtr
|
||||
gnc_schedXaction_dom_tree_create(SchedXaction *sx)
|
||||
{
|
||||
xmlNodePtr ret;
|
||||
xmlNodePtr fsNode;
|
||||
Timespec ts;
|
||||
GDate *date;
|
||||
|
||||
// FIXME: this should be the same as the def in io-gncxml-v2.c...
|
||||
ret = xmlNewNode( NULL, "gnc:schedxaction" );
|
||||
|
||||
xmlSetProp( ret, "version", schedxaction_version_string );
|
||||
|
||||
xmlAddChild( ret,
|
||||
guid_to_dom_tree("sx:id",
|
||||
xaccSchedXactionGetGUID(sx)) );
|
||||
|
||||
xmlNewTextChild( ret, NULL, "sx:name", xaccSchedXactionGetName(sx) );
|
||||
|
||||
xmlNewTextChild( ret, NULL, "sx:manual-conf",
|
||||
(xaccSchedXactionGetManual(sx) == 1 ? "t" : "f") );
|
||||
xmlAddChild( ret,
|
||||
gdate_to_dom_tree( "sx:start",
|
||||
xaccSchedXactionGetStartDate(sx) ) );
|
||||
date = xaccSchedXactionGetLastOccurDate(sx);
|
||||
|
||||
if ( g_date_valid( date ) ) {
|
||||
xmlAddChild( ret, gdate_to_dom_tree( "sx:last", date ) );
|
||||
}
|
||||
|
||||
if ( xaccSchedXactionHasOccurDef(sx) ) {
|
||||
xml_add_gint32( ret, "sx:num-occur",
|
||||
(gint32)xaccSchedXactionGetNumOccur(sx) );
|
||||
xml_add_gint32( ret, "sx:rem-occur",
|
||||
(gint32)xaccSchedXactionGetRemOccur(sx) );
|
||||
} else if ( xaccSchedXactionHasEndDate(sx) ) {
|
||||
xmlAddChild( ret,
|
||||
gdate_to_dom_tree( "sx:end",
|
||||
xaccSchedXactionGetEndDate(sx) ) );
|
||||
}
|
||||
|
||||
// output freq spec
|
||||
fsNode = xmlNewNode(NULL, "sx:freqspec");
|
||||
xmlAddChild( fsNode,
|
||||
gnc_freqSpec_dom_tree_create(
|
||||
xaccSchedXactionGetFreqSpec(sx)) );
|
||||
xmlAddChild( ret, fsNode );
|
||||
|
||||
// output kvp_frame
|
||||
{
|
||||
xmlNodePtr kvpnode =
|
||||
kvp_frame_to_dom_tree( "sx:slots",
|
||||
xaccSchedXactionGetSlots(sx) );
|
||||
if ( kvpnode )
|
||||
{
|
||||
xmlAddChild(ret, kvpnode);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_id_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
GUID *tmp = dom_tree_to_guid( node );
|
||||
g_return_val_if_fail( tmp, FALSE );
|
||||
xaccSchedXactionSetGUID( (SchedXaction*)sx, *tmp );
|
||||
g_free( tmp );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_name_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
gchar *tmp = dom_tree_to_text( node );
|
||||
g_return_val_if_fail( tmp, FALSE );
|
||||
xaccSchedXactionSetName( (SchedXaction*)sx, tmp );
|
||||
g_free( tmp );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_set_date( xmlNodePtr node, SchedXaction *sx,
|
||||
void (*settor)( SchedXaction *sx, GDate *d ) )
|
||||
{
|
||||
GDate *date;
|
||||
date = dom_tree_to_gdate( node );
|
||||
g_return_val_if_fail( date, FALSE );
|
||||
(*settor)( sx, date );
|
||||
g_date_free( date );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_start_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
return sx_set_date( node, (SchedXaction*)sx,
|
||||
xaccSchedXactionSetStartDate );
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_last_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
return sx_set_date( node, (SchedXaction*)sx,
|
||||
xaccSchedXactionSetLastOccurDate );
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_end_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
return sx_set_date( node, (SchedXaction*)sx,
|
||||
xaccSchedXactionSetEndDate );
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_freqspec_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
xmlNodePtr mark;
|
||||
FreqSpec *fs;
|
||||
|
||||
g_return_val_if_fail( node, FALSE );
|
||||
|
||||
fs = dom_tree_to_freqSpec( xmlGetLastChild( node ) );
|
||||
xaccSchedXactionSetFreqSpec( (SchedXaction*)sx, fs );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_manualConf_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
gchar *tmp;
|
||||
|
||||
tmp = dom_tree_to_text( node );
|
||||
g_return_val_if_fail( tmp, FALSE );
|
||||
|
||||
xaccSchedXactionSetManual( (SchedXaction*)sx,
|
||||
safe_strcmp(tmp, "t") == 0 );
|
||||
|
||||
g_free(tmp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_numOccur_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
gint64 numOccur;
|
||||
|
||||
if ( ! dom_tree_to_integer( node, &numOccur ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xaccSchedXactionSetNumOccur( (SchedXaction*)sx, numOccur );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_remOccur_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
gint64 remOccur;
|
||||
|
||||
if ( ! dom_tree_to_integer( node, &remOccur ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xaccSchedXactionSetRemOccur( (SchedXaction*)sx, remOccur );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
sx_slots_handler( xmlNodePtr node, gpointer sx )
|
||||
{
|
||||
kvp_frame *frm;
|
||||
frm = dom_tree_to_kvp_frame( node );
|
||||
xaccSchedXactionSetSlots( (SchedXaction*)sx, frm );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct dom_tree_handler sx_dom_handlers[] = {
|
||||
{ "sx:id", sx_id_handler, 1, 0 },
|
||||
{ "sx:name", sx_name_handler, 1, 0 },
|
||||
{ "sx:start", sx_start_handler, 1, 0 },
|
||||
{ "sx:last", sx_last_handler, 0, 0 },
|
||||
{ "sx:manual-conf", sx_manualConf_handler, 1, 0 },
|
||||
{ "sx:num-occur", sx_numOccur_handler, 0, 0 },
|
||||
{ "sx:rem-occur", sx_remOccur_handler, 0, 0 },
|
||||
{ "sx:end", sx_end_handler, 0, 0 },
|
||||
{ "sx:freqspec", sx_freqspec_handler, 1, 0 },
|
||||
{ "sx:slots", sx_slots_handler, 0, 0 },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gnc_schedXaction_end_handler(gpointer data_for_children,
|
||||
GSList* data_from_children, GSList* sibling_data,
|
||||
gpointer parent_data, gpointer global_data,
|
||||
gpointer *result, const gchar *tag)
|
||||
{
|
||||
SchedXaction *sx;
|
||||
gboolean successful = FALSE;
|
||||
xmlNodePtr achild;
|
||||
xmlNodePtr tree = (xmlNodePtr)data_for_children;
|
||||
gxpf_data *gdata = (gxpf_data*)global_data;
|
||||
|
||||
if ( parent_data ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( !tag ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_return_val_if_fail( tree, FALSE );
|
||||
|
||||
sx = xaccSchedXactionMalloc( NULL );
|
||||
|
||||
successful = dom_tree_generic_parse( tree, sx_dom_handlers, sx );
|
||||
|
||||
if ( successful ) {
|
||||
gdata->cb( tag, gdata->data, sx );
|
||||
} else {
|
||||
xmlElemDump( stdout, NULL, tree );
|
||||
xaccSchedXactionFree( sx );
|
||||
}
|
||||
|
||||
xmlFreeNode( tree );
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
sixtp*
|
||||
gnc_schedXaction_sixtp_parser_create(void)
|
||||
{
|
||||
return sixtp_dom_parser_new( gnc_schedXaction_end_handler, NULL, NULL );
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
tt_act_handler( xmlNodePtr node, gnc_template_xaction_data *txd )
|
||||
{
|
||||
Account *acc;
|
||||
acc = dom_tree_to_account( node );
|
||||
if ( acc == NULL ) {
|
||||
return FALSE;
|
||||
} else {
|
||||
txd->accts = g_list_append( txd->accts, acc );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
tt_trn_handler( xmlNodePtr node, gnc_template_xaction_data *txd )
|
||||
{
|
||||
Transaction *trn;
|
||||
trn = dom_tree_to_transaction( node );
|
||||
if ( trn == NULL ) {
|
||||
return FALSE;
|
||||
} else {
|
||||
txd->transactions = g_list_append( txd->transactions, trn );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct dom_tree_handler tt_dom_handlers[] = {
|
||||
{ "gnc:account", tt_act_handler, 0, 0 },
|
||||
{ "gnc:transaction", tt_trn_handler, 0, 0 },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gnc_template_transaction_end_handler(gpointer data_for_children,
|
||||
GSList* data_from_children, GSList* sibling_data,
|
||||
gpointer parent_data, gpointer global_data,
|
||||
gpointer *result, const gchar *tag)
|
||||
{
|
||||
gboolean successful = FALSE;
|
||||
xmlNodePtr achild;
|
||||
xmlNodePtr tree = (xmlNodePtr)data_for_children;
|
||||
gxpf_data *gdata = (gxpf_data*)global_data;
|
||||
GList *n;
|
||||
gnc_template_xaction_data *txd =
|
||||
g_new0( gnc_template_xaction_data, 1 );
|
||||
|
||||
// the DOM tree will have an account tree [the template group
|
||||
// and account] and a list of transactions [which will be
|
||||
// members of the template account].
|
||||
|
||||
|
||||
// we want to parse through the dom trees for each, placing
|
||||
// the null-parent account in the book's template-group slot,
|
||||
// the others under it, and the transactions as normal.
|
||||
|
||||
if ( parent_data ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( !tag ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_return_val_if_fail( tree, FALSE );
|
||||
|
||||
successful = dom_tree_generic_parse( tree, tt_dom_handlers, txd );
|
||||
|
||||
if ( successful ) {
|
||||
gdata->cb( tag, gdata->data, txd );
|
||||
} else {
|
||||
xmlElemDump( stdout, NULL, tree );
|
||||
}
|
||||
|
||||
// cleanup
|
||||
for ( n = txd->accts; n; n = n->next ) {
|
||||
n->data = NULL;
|
||||
}
|
||||
for ( n = txd->transactions; n; n = n->next ) {
|
||||
n->data = NULL;
|
||||
}
|
||||
g_list_free( txd->accts );
|
||||
g_list_free( txd->transactions );
|
||||
g_free( txd );
|
||||
xmlFreeNode( tree );
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
sixtp*
|
||||
gnc_template_transaction_sixtp_parser_create( void )
|
||||
{
|
||||
return sixtp_dom_parser_new( gnc_template_transaction_end_handler, NULL, NULL );
|
||||
}
|
||||
@@ -510,6 +510,34 @@ gnc_transaction_end_handler(gpointer data_for_children,
|
||||
return successful;
|
||||
}
|
||||
|
||||
Transaction *
|
||||
dom_tree_to_transaction( xmlNodePtr node )
|
||||
{
|
||||
Transaction *trn;
|
||||
gboolean successful;
|
||||
|
||||
g_return_val_if_fail(node, FALSE);
|
||||
|
||||
trn = xaccMallocTransaction();
|
||||
g_return_val_if_fail(trn, FALSE);
|
||||
xaccTransBeginEdit(trn);
|
||||
|
||||
successful = dom_tree_generic_parse(node, trn_dom_handlers, trn);
|
||||
|
||||
xaccTransCommitEdit(trn);
|
||||
|
||||
if ( !successful )
|
||||
{
|
||||
xmlElemDump(stdout, NULL, node);
|
||||
xaccTransBeginEdit(trn);
|
||||
xaccTransDestroy(trn);
|
||||
xaccTransCommitEdit(trn);
|
||||
trn = NULL;
|
||||
}
|
||||
|
||||
//xmlFreeNode(tree);
|
||||
return trn;
|
||||
}
|
||||
|
||||
sixtp*
|
||||
gnc_transaction_sixtp_parser_create(void)
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "sixtp.h"
|
||||
#include "gnc-pricedb.h"
|
||||
|
||||
#include "FreqSpec.h"
|
||||
#include "SchedXaction.h"
|
||||
|
||||
xmlNodePtr gnc_account_dom_tree_create(Account *act);
|
||||
sixtp* gnc_account_sixtp_parser_create(void);
|
||||
|
||||
@@ -50,5 +53,12 @@ Split* dom_tree_to_split(xmlNodePtr node);
|
||||
xmlNodePtr gnc_pricedb_dom_tree_create(GNCPriceDB *db);
|
||||
sixtp* gnc_pricedb_sixtp_parser_create(void);
|
||||
|
||||
xmlNodePtr gnc_schedXaction_dom_tree_create( SchedXaction *sx );
|
||||
sixtp* gnc_schedXaction_sixtp_parser_create(void);
|
||||
|
||||
xmlNodePtr gnc_freqSpec_dom_tree_create( FreqSpec *fs );
|
||||
sixtp* gnc_freqSpec_sixtp_parser_create(void);
|
||||
|
||||
sixtp* gnc_template_transaction_sixtp_parser_create(void);
|
||||
|
||||
#endif /* __GNC_XML_H__ */
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
#include "Group.h"
|
||||
|
||||
#include "Transaction.h"
|
||||
|
||||
#define GNC_V2_STRING "gnc-v2"
|
||||
|
||||
static void
|
||||
@@ -120,7 +122,58 @@ add_transaction_local(sixtp_gdv2 *data, Transaction *trn)
|
||||
|
||||
data->counter.transactions_loaded++;
|
||||
run_callback(data, "transaction");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
add_schedXaction_local(sixtp_gdv2 *data, SchedXaction *sx)
|
||||
{
|
||||
GList *list;
|
||||
list = gnc_book_get_schedxactions( data->book );
|
||||
list = g_list_append( list, sx );
|
||||
gnc_book_set_schedxactions( data->book, list );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
add_template_transaction_local( sixtp_gdv2 *data,
|
||||
gnc_template_xaction_data *txd )
|
||||
{
|
||||
GList *n;
|
||||
Account *tmpAcct;
|
||||
AccountGroup *acctGroup;
|
||||
|
||||
// expect a struct of:
|
||||
// . template accounts.
|
||||
// . transactions in those accounts.
|
||||
for ( n = txd->accts; n; n = n->next ) {
|
||||
if ( xaccAccountGetParent( (Account*)n->data ) == NULL ) {
|
||||
// remove the gnc_book_init-created account of
|
||||
// the same name
|
||||
acctGroup =
|
||||
gnc_book_get_template_group( data->book );
|
||||
tmpAcct =
|
||||
xaccGetAccountFromName( acctGroup,
|
||||
xaccAccountGetName( (Account*)n->data ) );
|
||||
if ( tmpAcct != NULL ) {
|
||||
xaccGroupRemoveAccount( acctGroup, tmpAcct );
|
||||
}
|
||||
|
||||
xaccGroupInsertAccount( acctGroup, (Account*)n->data );
|
||||
}
|
||||
|
||||
// This doesn't care about the "AccountCommitEdit-at-end"
|
||||
// paradigm of the normal accounts/transactions so much,
|
||||
// because there's only one template Account.
|
||||
xaccAccountCommitEdit( (Account*)n->data );
|
||||
}
|
||||
|
||||
for ( n = txd->transactions; n; n = n->next ) {
|
||||
// insert transactions into accounts
|
||||
add_transaction_local( data, (Transaction*)n->data );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -189,6 +242,10 @@ gnc_counter_end_handler(gpointer data_for_children,
|
||||
{
|
||||
sixdata->counter.commodities_total = val;
|
||||
}
|
||||
else if(safe_strcmp(type, "schedxaction") == 0)
|
||||
{
|
||||
sixdata->counter.schedXactions_total = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning("Unknown type: %s",
|
||||
@@ -218,6 +275,8 @@ print_counter_data(load_counter data)
|
||||
data.accounts_total, data.accounts_loaded);
|
||||
printf("Commodities: Total: %d, Loaded: %d\n",
|
||||
data.commodities_total, data.commodities_loaded);
|
||||
printf("Scheduled Tansactions: Total: %d, Loaded: %d\n",
|
||||
data.schedXactions_total, data.schedXactions_loaded);
|
||||
}
|
||||
|
||||
static const char *ACCOUNT_TAG = "gnc:account";
|
||||
@@ -225,6 +284,8 @@ static const char *PRICEDB_TAG = "gnc:pricedb";
|
||||
static const char *COMMODITY_TAG = "gnc:commodity";
|
||||
static const char *COUNT_DATA_TAG = "gnc:count-data";
|
||||
static const char *TRANSACTION_TAG = "gnc:transaction";
|
||||
static const char *SCHEDXACTION_TAG = "gnc:schedxaction";
|
||||
static const char *TEMPLATE_TRANSACTION_TAG = "gnc:template-transactions";
|
||||
|
||||
static gboolean
|
||||
generic_callback(const char *tag, gpointer globaldata, gpointer data)
|
||||
@@ -247,6 +308,14 @@ generic_callback(const char *tag, gpointer globaldata, gpointer data)
|
||||
{
|
||||
add_transaction_local(gd, (Transaction*)data);
|
||||
}
|
||||
else if(safe_strcmp(tag, SCHEDXACTION_TAG) == 0)
|
||||
{
|
||||
add_schedXaction_local(gd, (SchedXaction*)data);
|
||||
}
|
||||
else if(safe_strcmp(tag, TEMPLATE_TRANSACTION_TAG ) == 0 )
|
||||
{
|
||||
add_template_transaction_local( gd, (gnc_template_xaction_data*)data );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -270,6 +339,8 @@ gnc_book_load_from_xml_file_v2(
|
||||
gd->counter.transactions_total = 0;
|
||||
gd->counter.prices_loaded = 0;
|
||||
gd->counter.prices_total = 0;
|
||||
gd->counter.schedXactions_loaded = 0;
|
||||
gd->counter.schedXactions_total = 0;
|
||||
|
||||
{
|
||||
AccountGroup *g = gnc_book_get_group(book);
|
||||
@@ -297,6 +368,8 @@ gnc_book_load_from_xml_file_v2(
|
||||
COMMODITY_TAG, gnc_commodity_sixtp_parser_create(),
|
||||
ACCOUNT_TAG, gnc_account_sixtp_parser_create(),
|
||||
TRANSACTION_TAG, gnc_transaction_sixtp_parser_create(),
|
||||
SCHEDXACTION_TAG, gnc_schedXaction_sixtp_parser_create(),
|
||||
TEMPLATE_TRANSACTION_TAG, gnc_template_transaction_sixtp_parser_create(),
|
||||
NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
@@ -488,6 +561,39 @@ write_transactions(FILE *out, GNCBook *book)
|
||||
(gpointer) out);
|
||||
}
|
||||
|
||||
static void
|
||||
write_template_transaction_data( FILE *out, GNCBook *book )
|
||||
{
|
||||
fprintf( out, "<%s>\n", TEMPLATE_TRANSACTION_TAG );
|
||||
write_account_group( out, gnc_book_get_template_group(book) );
|
||||
xaccGroupForEachTransaction( gnc_book_get_template_group(book),
|
||||
xml_add_trn_data,
|
||||
(gpointer)out );
|
||||
fprintf( out, "</%s>\n", TEMPLATE_TRANSACTION_TAG );
|
||||
}
|
||||
|
||||
static void
|
||||
write_schedXactions( FILE *out, GNCBook *book )
|
||||
{
|
||||
GList *schedXactions;
|
||||
SchedXaction *tmpSX;
|
||||
xmlNodePtr node;
|
||||
|
||||
// get list of scheduled transactions from GNCBook
|
||||
schedXactions = gnc_book_get_schedxactions( book );
|
||||
|
||||
if ( schedXactions == NULL )
|
||||
return;
|
||||
|
||||
do {
|
||||
tmpSX = schedXactions->data;
|
||||
node = gnc_schedXaction_dom_tree_create( tmpSX );
|
||||
xmlElemDump( out, NULL, node );
|
||||
fprintf( out, "\n" );
|
||||
xmlFreeNode( node );
|
||||
} while ( (schedXactions = schedXactions->next) );
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_book_write_to_xml_file_v2(GNCBook *book, const char *filename)
|
||||
{
|
||||
@@ -506,6 +612,8 @@ gnc_book_write_to_xml_file_v2(GNCBook *book, const char *filename)
|
||||
xaccGroupGetNumSubAccounts(gnc_book_get_group(book)),
|
||||
"transaction",
|
||||
gnc_book_count_transactions(book),
|
||||
"schedxaction",
|
||||
g_list_length( gnc_book_get_schedxactions(book) ),
|
||||
NULL);
|
||||
|
||||
write_commodities(out, book);
|
||||
@@ -516,6 +624,10 @@ gnc_book_write_to_xml_file_v2(GNCBook *book, const char *filename)
|
||||
|
||||
write_transactions(out, book);
|
||||
|
||||
write_template_transaction_data(out, book);
|
||||
|
||||
write_schedXactions(out, book);
|
||||
|
||||
fprintf(out, "</" GNC_V2_STRING ">\n\n");
|
||||
write_emacs_trailer(out);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "Transaction.h"
|
||||
#include "gnc-commodity.h"
|
||||
#include "gnc-pricedb.h"
|
||||
#include "SchedXaction.h"
|
||||
|
||||
struct _load_counter_struct
|
||||
{
|
||||
@@ -52,6 +53,9 @@ struct _load_counter_struct
|
||||
|
||||
int prices_total;
|
||||
int prices_loaded;
|
||||
|
||||
int schedXactions_total;
|
||||
int schedXactions_loaded;
|
||||
};
|
||||
|
||||
typedef struct _load_counter_struct load_counter;
|
||||
@@ -63,6 +67,18 @@ struct sixtp_global_data_v2_struct
|
||||
void (*countCallback)(const char *type, load_counter counter);
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct used to pass the account group/accounts and trasnactions in
|
||||
* the <gnc:template-transactions> section between the parser in
|
||||
* gnc-schedxactions-xml-v2.c and the add-to-book callback in
|
||||
* io-gncxml-v2.c.
|
||||
**/
|
||||
typedef struct _gnc_template_xaction_data
|
||||
{
|
||||
GList *accts;
|
||||
GList *transactions;
|
||||
} gnc_template_xaction_data;
|
||||
|
||||
typedef struct sixtp_global_data_v2_struct sixtp_gdv2;
|
||||
|
||||
/* read in an account group from a file */
|
||||
@@ -78,5 +94,4 @@ gboolean gnc_book_write_to_xml_file_v2(GNCBook *book, const char *filename);
|
||||
*/
|
||||
gboolean gnc_is_xml_data_file_v2(const gchar *name);
|
||||
|
||||
|
||||
#endif /* __IO_GNCXML_V2_H__ */
|
||||
|
||||
@@ -121,9 +121,27 @@ Type: gint64
|
||||
Entities: Account
|
||||
Use: A boolean flag indicated whether the Account is tax-related.
|
||||
|
||||
Name: sched-xaction
|
||||
Type: frame
|
||||
Entities: Split in a SchedXaction
|
||||
Use: Storage for the various fields of a scheduled transaction's
|
||||
template Splits.
|
||||
|
||||
Name: sched-xaction/xfrm
|
||||
Type: GUID
|
||||
Entities: Split
|
||||
Use: The GUID of this Split's xfrm account.
|
||||
|
||||
Name: sched-xaction/amnt
|
||||
Type: string
|
||||
Entities: Split in a SchedXaction
|
||||
Use: The amount field of a SchedXaction might be a formula, which we
|
||||
store here.
|
||||
|
||||
Name: user-keys
|
||||
Type: frame
|
||||
Entities: All
|
||||
Use: This frame is used to store keys which are editable directly by
|
||||
the user. The program should not attach any semantics to keys
|
||||
under this frame.
|
||||
|
||||
|
||||
@@ -130,6 +130,9 @@ gint double_compare(double v1, double v2);
|
||||
|
||||
void kvp_value_delete(kvp_value * value);
|
||||
kvp_value * kvp_value_copy(const kvp_value * value);
|
||||
/**
|
||||
* Similar returns as strcmp.
|
||||
**/
|
||||
gint kvp_value_compare(const kvp_value *va, const kvp_value *vb);
|
||||
|
||||
/* list convenience funcs. */
|
||||
|
||||
@@ -135,8 +135,7 @@ timespec_to_dom_tree(const char *tag, const Timespec *spec)
|
||||
|
||||
date_str = timespec_sec_to_string(spec);
|
||||
|
||||
if(!date_str)
|
||||
{
|
||||
if(!date_str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -144,24 +143,41 @@ timespec_to_dom_tree(const char *tag, const Timespec *spec)
|
||||
|
||||
xmlNewTextChild(ret, NULL, "ts:date", date_str);
|
||||
|
||||
if(spec->tv_nsec > 0)
|
||||
{
|
||||
if(spec->tv_nsec > 0){
|
||||
ns_str = timespec_nsec_to_string(spec);
|
||||
if(ns_str)
|
||||
{
|
||||
if(ns_str){
|
||||
xmlNewTextChild(ret, NULL, "ts:ns", ns_str);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(date_str);
|
||||
if(ns_str)
|
||||
{
|
||||
if(ns_str){
|
||||
g_free(ns_str);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
xmlNodePtr
|
||||
gdate_to_dom_tree(const char *tag, GDate *date)
|
||||
{
|
||||
xmlNodePtr ret;
|
||||
gchar *date_str = NULL;
|
||||
|
||||
g_return_val_if_fail(date, NULL);
|
||||
date_str = g_new( gchar, 512 );
|
||||
|
||||
g_date_strftime( date_str, 512, "%Y-%m-%d", date );
|
||||
|
||||
ret = xmlNewNode(NULL, tag);
|
||||
|
||||
xmlNewTextChild(ret, NULL, "gdate", date_str);
|
||||
|
||||
g_free(date_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
xmlNodePtr
|
||||
gnc_numeric_to_dom_tree(const char *tag, const gnc_numeric *num)
|
||||
{
|
||||
@@ -331,3 +347,20 @@ kvp_frame_to_dom_tree(const char *tag, const kvp_frame *frame)
|
||||
return ret;
|
||||
}
|
||||
|
||||
xmlNodePtr guint_to_dom_tree(const char *tag, guint an_int)
|
||||
{
|
||||
xmlNodePtr ret;
|
||||
gchar *numstr;
|
||||
|
||||
numstr = g_strdup_printf( "%u", an_int );
|
||||
g_return_val_if_fail(numstr, NULL);
|
||||
|
||||
ret = xmlNewNode(NULL, tag);
|
||||
|
||||
xmlNodeAddContent(ret, numstr);
|
||||
|
||||
g_free(numstr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ xmlNodePtr commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c);
|
||||
xmlNodePtr timespec_to_dom_tree(const char *tag, const Timespec *spec);
|
||||
gchar * timespec_nsec_to_string(const Timespec *ts);
|
||||
gchar * timespec_sec_to_string(const Timespec *ts);
|
||||
xmlNodePtr gdate_to_dom_tree(const char *tag, GDate *spec);
|
||||
xmlNodePtr gnc_numeric_to_dom_tree(const char *tag, const gnc_numeric *num);
|
||||
xmlNodePtr kvp_frame_to_dom_tree(const char *tag, const kvp_frame *frame);
|
||||
xmlNodePtr guint_to_dom_tree(const char *tag, guint an_int);
|
||||
|
||||
gchar* double_to_string(double value);
|
||||
|
||||
|
||||
@@ -419,6 +419,7 @@ dom_tree_to_text(xmlNodePtr tree)
|
||||
return g_strdup("");
|
||||
}
|
||||
|
||||
|
||||
result = g_strdup("");
|
||||
|
||||
for(current = tree->xmlChildrenNode; current; current = current->next) {
|
||||
@@ -570,6 +571,71 @@ dom_tree_to_timespec(xmlNodePtr node)
|
||||
return ret;
|
||||
}
|
||||
|
||||
GDate*
|
||||
dom_tree_to_gdate(xmlNodePtr node)
|
||||
{
|
||||
/* Turn something like this
|
||||
|
||||
<sx:startdate>
|
||||
<gdate>2001-04-03</gdate>
|
||||
</sx:startdate>
|
||||
|
||||
into a GDate. If the xml is invalid, returns NULL. */
|
||||
|
||||
GDate *ret;
|
||||
gboolean seen_date = FALSE;
|
||||
xmlNodePtr n;
|
||||
|
||||
/* creates an invalid date */
|
||||
ret = g_date_new();
|
||||
|
||||
for(n = node->xmlChildrenNode; n; n = n->next) {
|
||||
switch(n->type) {
|
||||
case XML_COMMENT_NODE:
|
||||
break;
|
||||
case XML_ELEMENT_NODE:
|
||||
if(safe_strcmp("gdate", n->name) == 0) {
|
||||
if(seen_date) {
|
||||
goto failure;
|
||||
} else {
|
||||
gchar *content = dom_tree_to_text(n);
|
||||
gint year, month, day;
|
||||
if(!content) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if(sscanf(content, "%d-%d-%d", &year, &month, &day ) != 3) {
|
||||
g_free(content);
|
||||
goto failure;
|
||||
}
|
||||
g_free(content);
|
||||
seen_date = TRUE;
|
||||
g_date_set_dmy( ret, day, month, year );
|
||||
if( !g_date_valid( ret ) ) {
|
||||
g_warning("dom_tree_to_gdate: invalid date");
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PERR("dom_tree_to_gdate: unexpected sub-node.");
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
if(!seen_date) {
|
||||
g_warning("dom_tree_to_gdate: no gdate node found.");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return ret;
|
||||
failure:
|
||||
g_date_free( ret );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
gnc_commodity *
|
||||
dom_tree_to_commodity_ref_no_engine(xmlNodePtr node)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
#include "GNCId.h"
|
||||
|
||||
#include "FreqSpec.h"
|
||||
#include "Account.h"
|
||||
#include "Transaction.h"
|
||||
|
||||
GUID* dom_tree_to_guid(xmlNodePtr node);
|
||||
|
||||
gnc_commodity* dom_tree_to_commodity_ref(xmlNodePtr node);
|
||||
@@ -44,7 +48,10 @@ gnc_commodity* associate_commodity_ref_with_engine_commodity(
|
||||
gnc_commodity *com);
|
||||
gnc_commodity *dom_tree_to_commodity_ref_no_engine(xmlNodePtr node);
|
||||
|
||||
FreqSpec* dom_tree_to_freqSpec( xmlNodePtr node );
|
||||
|
||||
Timespec* dom_tree_to_timespec(xmlNodePtr node);
|
||||
GDate* dom_tree_to_gdate(xmlNodePtr node);
|
||||
gnc_numeric* dom_tree_to_gnc_numeric(xmlNodePtr node);
|
||||
gchar * dom_tree_to_text(xmlNodePtr tree);
|
||||
gboolean string_to_binary(const gchar *str, void **v, guint64 *data_len);
|
||||
@@ -62,6 +69,9 @@ kvp_value* dom_tree_to_frame_kvp_value(xmlNodePtr node);
|
||||
|
||||
gboolean dom_tree_to_integer(xmlNodePtr node, gint64 *daint);
|
||||
|
||||
// jsled-added...
|
||||
Account* dom_tree_to_account( xmlNodePtr node );
|
||||
Transaction* dom_tree_to_transaction( xmlNodePtr node );
|
||||
|
||||
struct dom_tree_handler
|
||||
{
|
||||
|
||||
@@ -258,6 +258,11 @@ gnc_cm_event_handler (GUID *entity,
|
||||
case GNC_ID_NONE:
|
||||
break;
|
||||
|
||||
case GNC_ID_SCHEDXACTION:
|
||||
case GNC_ID_FREQSPEC:
|
||||
DEBUG( "FIXME for GNC_ID %d", id_type );
|
||||
break;
|
||||
|
||||
default: {
|
||||
char guid_str[GUID_ENCODING_LENGTH+1];
|
||||
guid_to_string_buff (entity, guid_str);
|
||||
|
||||
@@ -25,6 +25,7 @@ libgncgnome_a_SOURCES = \
|
||||
dialog-transfer.c \
|
||||
dialog-userpass.c \
|
||||
dialog-utils.c \
|
||||
dialog-scheduledxaction.c \
|
||||
druid-commodity.c \
|
||||
druid-hierarchy.c \
|
||||
druid-qif-import.c \
|
||||
@@ -38,6 +39,7 @@ libgncgnome_a_SOURCES = \
|
||||
gnc-datedelta.c \
|
||||
gnc-dateedit.c \
|
||||
gnc-gpg.c \
|
||||
gnc-frequency.c \
|
||||
gnc-html-history.c \
|
||||
gnc-html-guppi.c \
|
||||
gnc-html.c \
|
||||
@@ -56,7 +58,8 @@ libgncgnome_a_SOURCES = \
|
||||
window-main-summarybar.c \
|
||||
window-reconcile.c \
|
||||
window-register.c \
|
||||
window-report.c
|
||||
window-report.c \
|
||||
dialog-nextrun.c
|
||||
|
||||
gnomeappdir = ${datadir}/gnome/apps/Applications
|
||||
|
||||
@@ -83,6 +86,7 @@ noinst_HEADERS = \
|
||||
dialog-totd.h \
|
||||
dialog-transfer.h \
|
||||
dialog-utils.h \
|
||||
dialog-scheduledxaction.h \
|
||||
druid-commodity.h \
|
||||
druid-hierarchy.h \
|
||||
druid-qif-import.h \
|
||||
@@ -95,6 +99,7 @@ noinst_HEADERS = \
|
||||
gnc-dateedit.h \
|
||||
gnc-dir.h \
|
||||
gnc-gpg.h \
|
||||
gnc-frequency.h \
|
||||
gnc-html-history.h \
|
||||
gnc-html-guppi.h \
|
||||
gnc-html.h \
|
||||
@@ -113,7 +118,8 @@ noinst_HEADERS = \
|
||||
window-main-summarybar.h \
|
||||
window-reconcile.h \
|
||||
window-register.h \
|
||||
window-report.h
|
||||
window-report.h \
|
||||
dialog-nextrun.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
.cvsignore \
|
||||
|
||||
560
src/gnome/dialog-nextrun.c
Normal file
560
src/gnome/dialog-nextrun.c
Normal file
@@ -0,0 +1,560 @@
|
||||
/********************************************************************\
|
||||
* dialog-nextrun.c - "since last run" dialog. *
|
||||
* Copyright (c) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gnome.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "gnc-engine-util.h"
|
||||
#include "FileDialog.h"
|
||||
#include "gnc-book.h"
|
||||
#include "Transaction.h"
|
||||
#include "Group.h"
|
||||
#include "gnc-numeric.h"
|
||||
#include "SchedXaction.h"
|
||||
#include "gnc-component-manager.h"
|
||||
#include "dialog-nextrun.h"
|
||||
#include "SplitLedger.h"
|
||||
#include "gnc-ui-util.h"
|
||||
#include "gnc-exp-parser.h"
|
||||
#include "dialog-utils.h"
|
||||
|
||||
#define DIALOG_NEXTRUN_CM_CLASS "dialog-nextrun"
|
||||
|
||||
static short module = MOD_SX;
|
||||
|
||||
typedef struct _toCreateTransaction {
|
||||
SchedXaction *sx;
|
||||
GDate *date;
|
||||
|
||||
gint clistRow;
|
||||
} toCreateTransaction;
|
||||
|
||||
typedef struct _sxSinceLastData {
|
||||
GtkWidget *nextrunDlg;
|
||||
GladeXML *gxml;
|
||||
GList /* <toCreateTransaction*> */ *transList;
|
||||
} sxSinceLastData;
|
||||
|
||||
static void nextrun_init( sxSinceLastData *sxsld );
|
||||
static void nextrun_close_handler( gpointer ud );
|
||||
static void nr_ok_clicked( GtkButton *b, gpointer ud );
|
||||
static void nr_next_clicked( GtkButton *b, gpointer ud );
|
||||
static void nr_prev_xaction_clicked( GtkButton *b, gpointer ud );
|
||||
static void nr_next_xaction_clicked( GtkButton *b, gpointer ud );
|
||||
|
||||
static void nextrun_destroy( GtkObject *o, gpointer ud );
|
||||
|
||||
static void slr_create_transactions( SchedXaction *sx, GDate *gd );
|
||||
|
||||
//int parse_vars_from_formula( const char *formula, GHashTable *varHash );
|
||||
|
||||
void
|
||||
gnc_ui_nextrun_dialog_create(void)
|
||||
{
|
||||
sxSinceLastData *sxsld = g_new0( sxSinceLastData, 1 );
|
||||
sxsld->gxml = gnc_glade_xml_new( "sched-xact.glade", "Since-Last-Run Instantiation" );
|
||||
sxsld->nextrunDlg = glade_xml_get_widget( sxsld->gxml, "Since-Last-Run Instantiation" );
|
||||
|
||||
nextrun_init( sxsld );
|
||||
}
|
||||
|
||||
static void
|
||||
nextrun_init( sxSinceLastData *sxsld )
|
||||
{
|
||||
GtkObject *o;
|
||||
int i;
|
||||
struct widgetNameSignalHandlerTuple {
|
||||
char *name;
|
||||
char *signal;
|
||||
void (*handlerFn)();
|
||||
} widgets[] = {
|
||||
{ "ok", "clicked", nr_ok_clicked },
|
||||
{ "next", "clicked", nr_next_clicked },
|
||||
{ "prev_xaction", "clicked", nr_prev_xaction_clicked },
|
||||
{ "next_xaction", "clicked", nr_next_xaction_clicked },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
gnc_register_gui_component( DIALOG_NEXTRUN_CM_CLASS,
|
||||
NULL,
|
||||
nextrun_close_handler,
|
||||
sxsld->nextrunDlg );
|
||||
|
||||
gtk_signal_connect( GTK_OBJECT(sxsld->nextrunDlg), "destroy",
|
||||
GTK_SIGNAL_FUNC( nextrun_destroy ), sxsld );
|
||||
|
||||
for ( i=0; widgets[i].name != NULL ; i++ ) {
|
||||
o = glade_xml_get_widget( sxsld->gxml, widgets[i].name );
|
||||
gtk_signal_connect( o, widgets[i].signal,
|
||||
GTK_SIGNAL_FUNC(widgets[i].handlerFn),
|
||||
sxsld );
|
||||
|
||||
}
|
||||
|
||||
o = glade_xml_get_widget( sxsld->gxml, "next" );
|
||||
gtk_signal_connect( o, "clicked",
|
||||
GTK_SIGNAL_FUNC(nr_next_clicked),
|
||||
sxsld );
|
||||
|
||||
o = glade_xml_get_widget( sxsld->gxml, "prev_xaction" );
|
||||
gtk_signal_connect( o, "clicked",
|
||||
GTK_SIGNAL_FUNC(nr_prev_xaction_clicked),
|
||||
sxsld );
|
||||
o = glade_xml_get_widget( sxsld->gxml, "next_xaction" );
|
||||
gtk_signal_connect( o, "clicked",
|
||||
GTK_SIGNAL_FUNC(nr_next_xaction_clicked),
|
||||
sxsld );
|
||||
|
||||
gtk_widget_show_all( sxsld->nextrunDlg );
|
||||
}
|
||||
|
||||
static void
|
||||
nextrun_close_handler( gpointer ud )
|
||||
{
|
||||
gnome_dialog_close( GNOME_DIALOG( ((sxSinceLastData*)ud)->nextrunDlg ) );
|
||||
}
|
||||
|
||||
static void
|
||||
nr_ok_clicked( GtkButton *b, gpointer ud )
|
||||
{
|
||||
sxSinceLastData *sxsld;
|
||||
GList *tctList;
|
||||
toCreateTransaction *tct;
|
||||
|
||||
sxsld = (sxSinceLastData*)ud;
|
||||
|
||||
tctList = sxsld->transList;
|
||||
if ( tctList == NULL ) {
|
||||
PERR( "no transactions to create\n" );
|
||||
}
|
||||
do {
|
||||
tct = (toCreateTransaction*)tctList->data;
|
||||
slr_create_transactions( tct->sx, tct->date );
|
||||
} while ( (tctList = tctList->next) );
|
||||
|
||||
nextrun_close_handler( ud );
|
||||
}
|
||||
|
||||
static void
|
||||
free_elts( gpointer data, gpointer user_data )
|
||||
{
|
||||
g_free( data );
|
||||
}
|
||||
|
||||
static void
|
||||
nr_next_clicked( GtkButton *b, gpointer ud )
|
||||
{
|
||||
sxSinceLastData *sxsld;
|
||||
GtkWidget *dlg;
|
||||
GtkObject *o;
|
||||
GtkCList *cl;
|
||||
time_t gdeDate;
|
||||
GList *sxList;
|
||||
GNCBook *book;
|
||||
SchedXaction *sx;
|
||||
GDate gd, *endDate;
|
||||
gchar buf[1024];
|
||||
gint row;
|
||||
char *rowText[2];
|
||||
toCreateTransaction *tct;
|
||||
|
||||
sxsld = (sxSinceLastData*)ud;
|
||||
o = glade_xml_get_widget( sxsld->gxml, "next_date" );
|
||||
gdeDate = gnome_date_edit_get_date( GNOME_DATE_EDIT(o) );
|
||||
|
||||
DEBUG( "Okay... I should run with a date of: %s", ctime(&gdeDate) );
|
||||
|
||||
// destroy the previous transactions
|
||||
// destroy all the toCreateTransactions
|
||||
if ( sxsld->transList != NULL ) {
|
||||
g_list_foreach( sxsld->transList, free_elts, NULL );
|
||||
g_list_free( sxsld->transList );
|
||||
sxsld->transList = NULL;
|
||||
}
|
||||
|
||||
book = gncGetCurrentBook();
|
||||
sxList = gnc_book_get_schedxactions( book );
|
||||
if ( sxList == NULL ) {
|
||||
PERR( "No scheduled transactions to play with\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
endDate = g_date_new();
|
||||
g_date_set_time( endDate, gdeDate );
|
||||
|
||||
o = glade_xml_get_widget( sxsld->gxml, "replace_with_register" );
|
||||
cl = GTK_CLIST(o);
|
||||
gtk_clist_clear( cl );
|
||||
|
||||
gd = *g_date_new();
|
||||
row = 0;
|
||||
do {
|
||||
sx = (SchedXaction*)sxList->data;
|
||||
g_date_set_time( &gd, time(NULL) );
|
||||
while ( g_date_compare( &gd, endDate ) <= 0 ) {
|
||||
g_date_strftime( buf, 1023, "%c", &gd );
|
||||
// add to clist [ahem... register... ahem]
|
||||
rowText[0] = xaccSchedXactionGetName( sx );
|
||||
rowText[1] = malloc( sizeof(char) * 256 ); // FIXME
|
||||
g_date_strftime( rowText[1], 255, "%c", &gd );
|
||||
|
||||
tct = g_new0( toCreateTransaction, 1 );
|
||||
tct->sx = sx;
|
||||
tct->date = g_date_new();
|
||||
*tct->date = gd;
|
||||
tct->clistRow = row;
|
||||
sxsld->transList = g_list_append( sxsld->transList, tct );
|
||||
|
||||
gtk_clist_insert( cl, row, rowText );
|
||||
row += 1;
|
||||
|
||||
gd = xaccSchedXactionGetInstanceAfter( sx, &gd );
|
||||
}
|
||||
} while ( (sxList = sxList->next) );
|
||||
|
||||
#if 0
|
||||
sxList = sxsld->transList;
|
||||
do {
|
||||
char buf[128];
|
||||
g_date_strftime( buf, 127, "%c",
|
||||
((toCreateTransaction*)sxList->data)->date );
|
||||
DEBUG( "List contains sx \"%s\" on date \"%s\"\n",
|
||||
xaccSchedXactionGetName( ((toCreateTransaction*)sxList->data)->sx ),
|
||||
buf );
|
||||
} while ( (sxList = sxList->next) );
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
static void
|
||||
nextrun_destroy( GtkObject *o, gpointer ud )
|
||||
{
|
||||
DEBUG( "nuttin' doin...\n" );
|
||||
}
|
||||
|
||||
static void
|
||||
nr_prev_xaction_clicked( GtkButton *b, gpointer ud )
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
nr_next_xaction_clicked( GtkButton *b, gpointer ud )
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_each_transaction( Transaction *t, void *d )
|
||||
{
|
||||
Transaction *newT;
|
||||
GDate *gd;
|
||||
GList *sList;
|
||||
GList *osList;
|
||||
Split *split;
|
||||
kvp_frame *split_kvpf;
|
||||
kvp_value *kvp_val;
|
||||
gboolean errFlag;
|
||||
|
||||
errFlag = FALSE;
|
||||
|
||||
DEBUG( "I'm seeing Transaction \"%s\"\n",
|
||||
xaccTransGetDescription( t ) );
|
||||
|
||||
gd = (GDate*)d;
|
||||
|
||||
newT = xaccMallocTransaction();
|
||||
xaccTransBeginEdit( newT );
|
||||
// the action and description/memo are in the template
|
||||
gnc_copy_trans_onto_trans( t, newT, FALSE, FALSE );
|
||||
|
||||
// the date is new [gd]
|
||||
xaccTransSetDate( newT,
|
||||
g_date_day( gd ),
|
||||
g_date_month( gd ),
|
||||
g_date_year( gd ) );
|
||||
|
||||
// the accounts and amounts are in the kvp_frames of the splits.
|
||||
osList = xaccTransGetSplitList( t );
|
||||
sList = xaccTransGetSplitList( newT );
|
||||
if ( (osList == NULL) || (sList == NULL) ) {
|
||||
PERR( "\tseen transaction w/o splits. :(\n" );
|
||||
return FALSE;
|
||||
}
|
||||
do {
|
||||
split = (Split*)sList->data;
|
||||
// Ick. This assumes that the split lists will be
|
||||
// ordered identically. :( I think it's fair to say
|
||||
// they will, but I'd rather not have to count on
|
||||
// it. --jsled
|
||||
split_kvpf = xaccSplitGetSlots( (Split*)osList->data );
|
||||
|
||||
DEBUG( "\tProcessing Split \"%s\"\n",
|
||||
xaccSplitGetMemo( split ) );
|
||||
|
||||
DEBUG( "\tkvp_frame: %s\n",
|
||||
kvp_frame_to_string( split_kvpf ) );
|
||||
|
||||
|
||||
// from-transaction of splits
|
||||
{
|
||||
GUID *acct_guid;
|
||||
Account *acct;
|
||||
// contains the guid of the split's actual account.
|
||||
kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/xfrm" );
|
||||
if ( kvp_val == NULL ) {
|
||||
PERR( "Null kvp_val for xfrm\n" );
|
||||
}
|
||||
acct_guid = kvp_value_get_guid( kvp_val );
|
||||
acct = xaccAccountLookup( acct_guid );
|
||||
DEBUG( "Got account with name \"%s\"\n",
|
||||
xaccAccountGetName( acct ) );
|
||||
//xaccSplitSetAccount( split, acct );
|
||||
xaccAccountInsertSplit( acct, split );
|
||||
}
|
||||
// credit/debit formulas
|
||||
{
|
||||
char *str;
|
||||
gnc_numeric credit_num;
|
||||
gnc_numeric debit_num;
|
||||
gnc_numeric final;
|
||||
int gncn_error;
|
||||
|
||||
kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/credit_formula" );
|
||||
str = kvp_value_get_string( kvp_val );
|
||||
credit_num = gnc_numeric_create( 0, 1 );
|
||||
if ( str != NULL ) {
|
||||
|
||||
printf( "---------------\n" );
|
||||
printf( "Parsing formula:\n" );
|
||||
//parse_vars_from_formula( str, NULL );
|
||||
printf( "---------------\n" );
|
||||
|
||||
xaccParseAmount( str, TRUE, &credit_num, NULL );
|
||||
//string_to_gnc_numeric( str, &credit_num );
|
||||
printf( "gnc_numeric::credit: \"%s\" -> \"%s\"\n",
|
||||
str, gnc_numeric_to_string( credit_num ) );
|
||||
}
|
||||
|
||||
kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/debit_formula" );
|
||||
str = kvp_value_get_string( kvp_val );
|
||||
|
||||
debit_num = gnc_numeric_create( 0, 1 );
|
||||
if ( str != NULL ) {
|
||||
|
||||
printf( "---------------\n" );
|
||||
printf( "Parsing formula:\n" );
|
||||
//parse_vars_from_formula( str, NULL );
|
||||
printf( "---------------\n" );
|
||||
|
||||
xaccParseAmount( str, TRUE, &debit_num, NULL );
|
||||
//string_to_gnc_numeric( str, &debit_num );
|
||||
printf( "gnc_numeric::debit: \"%s\" -> \"%s\"\n",
|
||||
str, gnc_numeric_to_string( debit_num ) );
|
||||
}
|
||||
|
||||
final = gnc_numeric_sub_fixed( debit_num,
|
||||
credit_num );
|
||||
|
||||
gncn_error = gnc_numeric_check( final );
|
||||
if ( gncn_error != GNC_ERROR_OK ) {
|
||||
printf( "Error %d in final gnc_numeric value\n", gncn_error );
|
||||
errFlag = TRUE;
|
||||
break;
|
||||
}
|
||||
printf( "gnc_numeric::final: \"%s\"\n",
|
||||
gnc_numeric_to_string( final ) );
|
||||
xaccSplitSetValue( split, final );
|
||||
}
|
||||
#if 0
|
||||
kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/shares" );
|
||||
kvp_val = kvp_frame_get_slot( split_kvpf, "sched-xaction/amnt" );
|
||||
#endif // 0
|
||||
} while ( (sList = sList->next) && (osList = osList->next) );
|
||||
|
||||
if ( errFlag ) {
|
||||
printf( "Some error in newT creation\n" );
|
||||
xaccTransRollbackEdit( newT );
|
||||
} else {
|
||||
xaccTransCommitEdit( newT );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
slr_create_transactions( SchedXaction *sx, GDate *gd )
|
||||
{
|
||||
AccountGroup *ag;
|
||||
Account *acct;
|
||||
char *id;
|
||||
|
||||
// get template account group
|
||||
ag = gnc_book_get_template_group( gncGetCurrentBook() );
|
||||
id = guid_to_string( xaccSchedXactionGetGUID(sx) );
|
||||
acct = xaccGetAccountFromName( ag, id );
|
||||
printf( "Got account \"%s\"\n",
|
||||
xaccAccountGetName( acct ) );
|
||||
g_free( id );
|
||||
|
||||
xaccAccountForEachTransaction( acct,
|
||||
create_each_transaction,
|
||||
gd );
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Parses in-fix mathematical formulas using the standard operators
|
||||
* [+-/%*], and '(', ')' grouping.
|
||||
*
|
||||
* Any strings are placed in the GHashTable as variables. The value of
|
||||
* each key in the hash-table is a struct of the form:
|
||||
* { const char *varStr;
|
||||
* gint idx;
|
||||
* gint len; };
|
||||
*
|
||||
**/
|
||||
int
|
||||
parse_vars_from_formula( const char *formula, GHashTable *varHash )
|
||||
{
|
||||
gnc_numeric num_foo;
|
||||
char *foo;
|
||||
GList *list;
|
||||
|
||||
gnc_exp_parser_init();
|
||||
if ( ! gnc_exp_parser_parse( formula, &num_foo, &foo ) ) {
|
||||
printf( "Error parsing at \"%s\": %s\n",
|
||||
foo, gnc_exp_parser_error_string() );
|
||||
}
|
||||
printf( "Successful parse...\n" );
|
||||
list = gnc_exp_parser_get_variable_names();
|
||||
if ( list == NULL ) {
|
||||
printf( "NULL variable list\n" );
|
||||
} else {
|
||||
do {
|
||||
printf( "Variable \"%s\"\n",
|
||||
list->data );
|
||||
} while ( (list = list->next) );
|
||||
}
|
||||
|
||||
gnc_exp_parser_shutdown();
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
#if 0
|
||||
GScanner *varScanner;
|
||||
GTokenType tok;
|
||||
|
||||
varScanner = g_scanner_new( NULL );
|
||||
g_scanner_set_scope( varScanner, 0 );
|
||||
g_scanner_freeze_symbol_table( varScanner );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, "(", (gpointer)"left-paren" );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, ")", (gpointer)"right-paren" );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, "+", (gpointer)"plus" );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, "-", (gpointer)"minus" );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, "/", (gpointer)"div" );
|
||||
g_scanner_scope_add_symbol( varScanner, 0, "*", (gpointer)"mult" );
|
||||
g_scanner_thaw_symbol_table( varScanner );
|
||||
|
||||
g_scanner_input_text( varScanner, formula, strlen( formula ) );
|
||||
|
||||
do {
|
||||
tok = g_scanner_get_next_token( varScanner );
|
||||
printf( "tok: " );
|
||||
switch ( varScanner->token ) {
|
||||
case G_TOKEN_EOF:
|
||||
printf( "EOF" ); break;
|
||||
case G_TOKEN_LEFT_PAREN:
|
||||
printf( "(" ); break;
|
||||
case G_TOKEN_RIGHT_PAREN:
|
||||
printf( ")" ); break;
|
||||
case G_TOKEN_LEFT_CURLY:
|
||||
printf( "{" ); break;
|
||||
case G_TOKEN_RIGHT_CURLY:
|
||||
printf( "}" ); break;
|
||||
case G_TOKEN_LEFT_BRACE:
|
||||
printf( "[" ); break;
|
||||
case G_TOKEN_RIGHT_BRACE:
|
||||
printf( "]" ); break;
|
||||
case G_TOKEN_EQUAL_SIGN:
|
||||
printf( "=" ); break;
|
||||
case G_TOKEN_COMMA:
|
||||
printf( "," ); break;
|
||||
case G_TOKEN_NONE:
|
||||
printf( "NONE" ); break;
|
||||
case G_TOKEN_ERROR:
|
||||
printf( "ERROR(%d)", varScanner->value.v_error ); break;
|
||||
case G_TOKEN_CHAR:
|
||||
printf( "CHAR(%c)", varScanner->value.v_char ); break;
|
||||
case G_TOKEN_BINARY:
|
||||
printf( "BINARY" ); break;
|
||||
case G_TOKEN_OCTAL:
|
||||
printf( "OCTAL(%ul)", varScanner->value.v_octal ); break;
|
||||
case G_TOKEN_INT:
|
||||
printf( "INT(%ul)", varScanner->value.v_int ); break;
|
||||
case G_TOKEN_HEX:
|
||||
printf( "HEX(%ul)", varScanner->value.v_hex ); break;
|
||||
case G_TOKEN_FLOAT:
|
||||
printf( "FLOAT(%f)", varScanner->value.v_float ); break;
|
||||
case G_TOKEN_STRING:
|
||||
printf( "STRING(%s)", varScanner->value.v_string ); break;
|
||||
case G_TOKEN_SYMBOL:
|
||||
printf( "SYMBOL(%s)", (gchar*)varScanner->value.v_symbol ); break;
|
||||
case G_TOKEN_IDENTIFIER:
|
||||
printf( "IDENT(%s)", varScanner->value.v_identifier ); break;
|
||||
case G_TOKEN_IDENTIFIER_NULL:
|
||||
printf( "NULL_IDENT" ); break;
|
||||
case G_TOKEN_COMMENT_SINGLE:
|
||||
case G_TOKEN_COMMENT_MULTI:
|
||||
printf( "COMMENT(%s)", varScanner->value.v_comment ); break;
|
||||
case G_TOKEN_LAST:
|
||||
printf( "END" ); break;
|
||||
default:
|
||||
printf( "UNK" ); break;
|
||||
};
|
||||
printf( "\n" );
|
||||
} while ( (varScanner->token != G_TOKEN_LAST) &&
|
||||
(varScanner->token != G_TOKEN_EOF) &&
|
||||
(varScanner->token != G_TOKEN_NONE) );
|
||||
return 1;
|
||||
/*
|
||||
"0.33 * ( base + ld ) + (0.25 * internet)":
|
||||
|
||||
tok: FLOAT(0.330000)
|
||||
tok: UNK
|
||||
tok: )
|
||||
tok: IDENT(base)
|
||||
tok: UNK
|
||||
tok: IDENT(ld)
|
||||
tok: (
|
||||
tok: UNK
|
||||
tok: )
|
||||
tok: FLOAT(0.250000)
|
||||
tok: UNK
|
||||
tok: IDENT(internet)
|
||||
tok: (
|
||||
tok: EOF
|
||||
*/
|
||||
|
||||
#endif // 0
|
||||
23
src/gnome/dialog-nextrun.h
Normal file
23
src/gnome/dialog-nextrun.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/********************************************************************\
|
||||
* dialog-nextrun.h - Beginnings of "since last run" dialog. *
|
||||
* Copyright (c) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
void gnc_ui_nextrun_dialog_create( void );
|
||||
1303
src/gnome/dialog-scheduledxaction.c
Normal file
1303
src/gnome/dialog-scheduledxaction.c
Normal file
File diff suppressed because it is too large
Load Diff
51
src/gnome/dialog-scheduledxaction.h
Normal file
51
src/gnome/dialog-scheduledxaction.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/********************************************************************\
|
||||
* dialog-scheduledxaction.h : dialogs for a scheduled transactions *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef __DIALOG_SCHEDULEDXACTION_H_
|
||||
#define __DIALOG_SCHEDULEDXACTION_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <gnome.h>
|
||||
#include "SchedXaction.h"
|
||||
|
||||
struct _SchedXactionDialog;
|
||||
struct _SchedXactionEditorDialog;
|
||||
|
||||
typedef struct _SchedXactionDialog SchedXactionDialog;
|
||||
typedef struct _SchedXactionEditorDialog SchedXactionEditorDialog;
|
||||
|
||||
SchedXactionDialog * gnc_ui_scheduled_xaction_dialog_create(void);
|
||||
void gnc_ui_scheduled_xaction_dialog_destroy(SchedXactionDialog *sxd);
|
||||
void row_select_handler( GtkCList *clist, gint row, gint col, GdkEventButton *event, gpointer d );
|
||||
|
||||
SchedXactionEditorDialog *
|
||||
gnc_ui_scheduled_xaction_editor_dialog_create( SchedXactionDialog *sxd,
|
||||
SchedXaction *sx );
|
||||
void gnc_ui_scheduled_xaction_editor_dialog_destroy(SchedXactionEditorDialog *sxd);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* . date-entries should back-stop each other?
|
||||
* . modify gtkentry to prohibit fracation num-occurance values.
|
||||
**/
|
||||
@@ -15,7 +15,8 @@ glade_DATA = \
|
||||
stocks.glade \
|
||||
tax.glade \
|
||||
transfer.glade \
|
||||
userpass.glade
|
||||
userpass.glade \
|
||||
sched-xact.glade
|
||||
|
||||
STRING_FILES = \
|
||||
account_strings.c \
|
||||
@@ -33,6 +34,7 @@ STRING_FILES = \
|
||||
stocks_strings.c \
|
||||
tax_strings.c \
|
||||
transfer_strings.c \
|
||||
userpass_strings.c
|
||||
userpass_strings.c \
|
||||
sched-xact_strings.c
|
||||
|
||||
EXTRA_DIST = $(glade_DATA) $(STRING_FILES)
|
||||
|
||||
2790
src/gnome/glade/sched-xact.glade
Normal file
2790
src/gnome/glade/sched-xact.glade
Normal file
File diff suppressed because it is too large
Load Diff
349
src/gnome/glade/sched-xact_strings.c
Normal file
349
src/gnome/glade/sched-xact_strings.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Translatable strings file generated by Glade.
|
||||
* Add this file to your project's POTFILES.in.
|
||||
* DO NOT compile it as part of your application.
|
||||
*/
|
||||
|
||||
gchar *s = N_("Edit Scheduled Transaction");
|
||||
gchar *s = N_("Name:");
|
||||
gchar *s = N_("Creation Options");
|
||||
gchar *s = N_("Create automatically.");
|
||||
gchar *s = N_("Notify me when created.");
|
||||
gchar *s = N_("End");
|
||||
gchar *s = N_("No End");
|
||||
gchar *s = N_("End Date:");
|
||||
gchar *s = N_("Number of Occurances:");
|
||||
gchar *s = N_("Recurrance Frequency");
|
||||
gchar *s = N_("Template Transaction");
|
||||
gchar *s = N_("Record");
|
||||
gchar *s = N_("REPLACEME with the Register control box...");
|
||||
gchar *s = N_("This window should never be realized.");
|
||||
gchar *s = N_("Frequency:");
|
||||
gchar *s = N_("None");
|
||||
gchar *s = N_("Once");
|
||||
gchar *s = N_("Daily");
|
||||
gchar *s = N_("Daily [M-F]");
|
||||
gchar *s = N_("Weekly");
|
||||
gchar *s = N_("Bi-Weekly");
|
||||
gchar *s = N_("Semi-Monthly");
|
||||
gchar *s = N_("Monthly");
|
||||
gchar *s = N_("Quarterly");
|
||||
gchar *s = N_("Tri-Anually");
|
||||
gchar *s = N_("Semi-Yearly");
|
||||
gchar *s = N_("Yearly");
|
||||
gchar *s = N_("Start Date:");
|
||||
gchar *s = N_("Not scheduled");
|
||||
gchar *s = N_("None");
|
||||
gchar *s = N_("Select occurrence date above.");
|
||||
gchar *s = N_("Once");
|
||||
gchar *s = N_("Every ");
|
||||
gchar *s = N_("days.");
|
||||
gchar *s = N_("Example");
|
||||
gchar *s = N_("Daily");
|
||||
gchar *s = N_("Every ");
|
||||
gchar *s = N_("weeks.");
|
||||
gchar *s = N_("Example");
|
||||
gchar *s = N_("Daily [M-F]");
|
||||
gchar *s = N_("Every");
|
||||
gchar *s = N_("weeks.");
|
||||
gchar *s = N_("Days");
|
||||
gchar *s = N_("Sunday");
|
||||
gchar *s = N_("Monday");
|
||||
gchar *s = N_("Tuesday");
|
||||
gchar *s = N_("Wednesday");
|
||||
gchar *s = N_("Thursday");
|
||||
gchar *s = N_("Friday");
|
||||
gchar *s = N_("Saturday");
|
||||
gchar *s = N_("Example");
|
||||
gchar *s = N_("Weekly");
|
||||
gchar *s = N_("Select initial date, above.");
|
||||
gchar *s = N_("Bi-Weekly");
|
||||
gchar *s = N_("Every");
|
||||
gchar *s = N_("months.");
|
||||
gchar *s = N_("First on the:");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("then on the:");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Example");
|
||||
gchar *s = N_("Semi-Monthly");
|
||||
gchar *s = N_("Every ");
|
||||
gchar *s = N_("months.");
|
||||
gchar *s = N_("On the");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Example");
|
||||
gchar *s = N_("Monthly");
|
||||
gchar *s = N_("Occuring in");
|
||||
gchar *s = N_("Jan, Apr, Jul, Oct");
|
||||
gchar *s = N_("Feb, May, Aug, Nov");
|
||||
gchar *s = N_("Mar, Jun, Sep, Dec");
|
||||
gchar *s = N_("On the");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Quarterly");
|
||||
gchar *s = N_("Occuring in");
|
||||
gchar *s = N_("Jan, May, Sep");
|
||||
gchar *s = N_("Feb, Apr, Oct");
|
||||
gchar *s = N_("Mar, Jun, Nov");
|
||||
gchar *s = N_("Apr, Jul, Dec");
|
||||
gchar *s = N_("On the");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Tri-Yearly");
|
||||
gchar *s = N_("Occuring in");
|
||||
gchar *s = N_("Jan, Jul");
|
||||
gchar *s = N_("Feb, Aug");
|
||||
gchar *s = N_("Mar, Sep");
|
||||
gchar *s = N_("Apr, Oct");
|
||||
gchar *s = N_("May, Nov");
|
||||
gchar *s = N_("Jun, Dec");
|
||||
gchar *s = N_("On the");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Semi-Yearly");
|
||||
gchar *s = N_("Every");
|
||||
gchar *s = N_("year(s).");
|
||||
gchar *s = N_("Month");
|
||||
gchar *s = N_("January");
|
||||
gchar *s = N_("February");
|
||||
gchar *s = N_("March");
|
||||
gchar *s = N_("April");
|
||||
gchar *s = N_("May");
|
||||
gchar *s = N_("June");
|
||||
gchar *s = N_("July");
|
||||
gchar *s = N_("August");
|
||||
gchar *s = N_("September");
|
||||
gchar *s = N_("October");
|
||||
gchar *s = N_("November");
|
||||
gchar *s = N_("December");
|
||||
gchar *s = N_("Day");
|
||||
gchar *s = N_("1st");
|
||||
gchar *s = N_("2nd");
|
||||
gchar *s = N_("3rd");
|
||||
gchar *s = N_("4th");
|
||||
gchar *s = N_("5th");
|
||||
gchar *s = N_("6th");
|
||||
gchar *s = N_("7th");
|
||||
gchar *s = N_("8th");
|
||||
gchar *s = N_("9th");
|
||||
gchar *s = N_("10th");
|
||||
gchar *s = N_("11th");
|
||||
gchar *s = N_("12th");
|
||||
gchar *s = N_("13th");
|
||||
gchar *s = N_("14th");
|
||||
gchar *s = N_("15th");
|
||||
gchar *s = N_("16th");
|
||||
gchar *s = N_("17th");
|
||||
gchar *s = N_("18th");
|
||||
gchar *s = N_("19th");
|
||||
gchar *s = N_("20th");
|
||||
gchar *s = N_("21st");
|
||||
gchar *s = N_("22nd");
|
||||
gchar *s = N_("23rd");
|
||||
gchar *s = N_("24th");
|
||||
gchar *s = N_("25th");
|
||||
gchar *s = N_("26th");
|
||||
gchar *s = N_("27th");
|
||||
gchar *s = N_("28th");
|
||||
gchar *s = N_("[29th]");
|
||||
gchar *s = N_("[30th]");
|
||||
gchar *s = N_("[31st]");
|
||||
gchar *s = N_("[last day]");
|
||||
gchar *s = N_("Yearly");
|
||||
gchar *s = N_("Scheduled Transactions");
|
||||
gchar *s = N_("Name");
|
||||
gchar *s = N_("Frequency");
|
||||
gchar *s = N_("Next");
|
||||
gchar *s = N_("New");
|
||||
gchar *s = N_("Edit");
|
||||
gchar *s = N_("Delete");
|
||||
gchar *s = N_("Since Last Run...");
|
||||
gchar *s = N_("Next run date...");
|
||||
gchar *s = N_("To-create...");
|
||||
gchar *s = N_("Name");
|
||||
gchar *s = N_("Date");
|
||||
gchar *s = N_("Variable");
|
||||
gchar *s = N_("Value");
|
||||
gchar *s = N_("What should this be?");
|
||||
@@ -7,6 +7,12 @@
|
||||
* This file was part of the Gnome Library. It was modifed by
|
||||
* Dave Peticolas <peticola@cs.ucdavis.edu> for use in GnuCash.
|
||||
*
|
||||
* 2001.05.13T1647 [PDT], #gnucash:
|
||||
* <jsled> dave_p: So the header for gnc-dateedit.h is a bit light
|
||||
* on _why_ such a thing was done... any help?
|
||||
* <dave_p> jsled: gnome date edit isn't i18n'd properly. also, we
|
||||
* added the register date hotkeys.
|
||||
*
|
||||
* GnuCash is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
@@ -23,8 +29,7 @@
|
||||
* Free Software Foundation Voice: +1-617-542-5942
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org
|
||||
*
|
||||
*/
|
||||
* */
|
||||
/*
|
||||
@NOTATION@
|
||||
*/
|
||||
|
||||
1014
src/gnome/gnc-frequency.c
Normal file
1014
src/gnome/gnc-frequency.c
Normal file
File diff suppressed because it is too large
Load Diff
89
src/gnome/gnc-frequency.h
Normal file
89
src/gnome/gnc-frequency.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/********************************************************************\
|
||||
* gnc-frequency.h -- GnuCash widget for frequency editing. *
|
||||
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef GNC_FREQUENCY_H
|
||||
#define GNC_FREQUENCY_H
|
||||
|
||||
#include <gnome.h>
|
||||
#include "FreqSpec.h"
|
||||
#include "dialog-utils.h"
|
||||
|
||||
BEGIN_GNOME_DECLS
|
||||
|
||||
#define GNC_FREQUENCY(obj) GTK_CHECK_CAST(obj, gnc_frequency_get_type(), GNCFrequency)
|
||||
#define GNC_FREQENCY_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gnc_frequency_get_type(), GNCFrequency)
|
||||
#define GNC_IS_FREQUENCY(obj) GTK_CHECK_TYPE(obj, gnc_frequency_get_type())
|
||||
|
||||
/**
|
||||
* A GNCFrequency is a VBox containing a scrollable GtkNotebook which
|
||||
* allows the user to specify the frequency [of a scheduled
|
||||
* transaction or budgeting category, for instance], manipulating a
|
||||
* FreqSpec object in the process.
|
||||
**/
|
||||
typedef struct _GNCFrequency {
|
||||
GtkVBox widget;
|
||||
|
||||
GtkVBox *vb;
|
||||
GtkNotebook *nb;
|
||||
GtkOptionMenu *freqOpt;
|
||||
GnomeDateEdit *startDate;
|
||||
GladeXML *gxml;
|
||||
} GNCFrequency;
|
||||
|
||||
typedef struct _GNCFrequencyClass {
|
||||
GtkVBoxClass parent_class;
|
||||
void (*value_changed) (GNCFrequency *gf);
|
||||
} GNCFrequencyClass;
|
||||
|
||||
struct pageDataTuple {
|
||||
int idx;
|
||||
UIFreqType uiFTVal;
|
||||
char *name;
|
||||
};
|
||||
|
||||
guint gnc_frequency_get_type( void );
|
||||
|
||||
/**
|
||||
* For the default freq spec widget, use 'NULL'.
|
||||
**/
|
||||
GtkWidget * gnc_frequency_new( FreqSpec *fs );
|
||||
void gnc_frequency_init( GNCFrequency *gf );
|
||||
/**
|
||||
* Sets up the given GNCFrequency with the given FreqSpec and
|
||||
* UIFreqSpec. If the FreqSpec is NULL, then the default value is
|
||||
* Daily; if the UIFreqSpec is not NONE, then that value is the
|
||||
* default. If the FreqSpec is non-NULL, then it really should agree
|
||||
* with the UIFreqSpec; this is considered a 'critical' error.
|
||||
**/
|
||||
void gnc_frequency_setup( GNCFrequency *gf, FreqSpec *fs );
|
||||
|
||||
/**
|
||||
* Saves the state of the GNCFrequenecy widget into the given FreqSpec
|
||||
* and UIFreqSpec.
|
||||
* Places the start date in outStartDate, if it's not null.
|
||||
**/
|
||||
void gnc_frequency_save_state( GNCFrequency *gf, FreqSpec *fs, GDate *outStartDate );
|
||||
|
||||
END_GNOME_DECLS
|
||||
|
||||
#endif // !defined( GNC_FREQUENCY_H )
|
||||
@@ -207,7 +207,7 @@ gnc_verify_dialog_parented(gncUIWidget parent, const char *message,
|
||||
if (parent != NULL)
|
||||
gnome_dialog_set_parent(GNOME_DIALOG(verify_box), GTK_WINDOW(parent));
|
||||
|
||||
gnome_dialog_set_default(GNOME_DIALOG(verify_box), yes_is_default ? 0 : 1);
|
||||
gnome_dialog_set_default(GNOME_DIALOG(verify_box), (yes_is_default ? 0 : 1));
|
||||
|
||||
return (gnome_dialog_run_and_close(GNOME_DIALOG(verify_box)) == 0);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#ifndef __QUERY_USER_H__
|
||||
#define __QUERY_USER_H__
|
||||
|
||||
// +jsled: for line below.
|
||||
#include "gnc-ui.h"
|
||||
|
||||
void gnc_info_dialog(const char *message);
|
||||
void gnc_info_dialog_parented(GtkWindow *parent, const char *message);
|
||||
|
||||
@@ -30,4 +33,7 @@ void gnc_warning_dialog(const char *message);
|
||||
|
||||
void gnc_error_dialog_parented(GtkWindow *parent, const char *message);
|
||||
|
||||
// +jsled: export so dialog-scheduledxaction can see it...
|
||||
gboolean gnc_verify_dialog_parented(gncUIWidget parent, const char *message, gboolean yes_is_default);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
#include "dialog-totd.h"
|
||||
#include "dialog-transfer.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "dialog-scheduledxaction.h"
|
||||
#include "dialog-nextrun.h"
|
||||
|
||||
#include "window-help.h"
|
||||
#include "window-main.h"
|
||||
@@ -880,6 +882,18 @@ gnc_main_window_fincalc_cb(GtkWidget *widget, gpointer data) {
|
||||
gnc_ui_fincalc_dialog_create();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_ui_mainWindow_scheduled_xaction_cb(GtkWidget *widget, gpointer data)
|
||||
{
|
||||
gnc_ui_scheduled_xaction_dialog_create();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_ui_mainWindow_nextrun_cb( GtkWidget *widget, gpointer d )
|
||||
{
|
||||
gnc_ui_nextrun_dialog_create();
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_main_window_gl_cb(GtkWidget *widget, gpointer data) {
|
||||
xaccLedgerDisplay *ld;
|
||||
@@ -1100,12 +1114,18 @@ gnc_main_window_create_menus(GNCMainInfo * maininfo) {
|
||||
GNOMEUIINFO_END
|
||||
};
|
||||
|
||||
static GnomeUIInfo gnc_developer_menu_template[] =
|
||||
{
|
||||
GNOMEUIINFO_END
|
||||
};
|
||||
|
||||
static GnomeUIInfo gnc_main_menu_template[] =
|
||||
{
|
||||
GNOMEUIINFO_MENU_FILE_TREE(gnc_file_menu_template),
|
||||
GNOMEUIINFO_SUBTREE(N_("_Tools"), gnc_tools_menu_template),
|
||||
GNOMEUIINFO_SUBTREE(N_("_Settings"), gnc_settings_menu_template),
|
||||
GNOMEUIINFO_SUBTREE(N_("_Windows"), gnc_windows_menu_template),
|
||||
// GNOEMUIINFO_SUBTREE(N_("_Developer Options"), gnc_developer_menu_template),
|
||||
GNOMEUIINFO_MENU_HELP_TREE(gnc_help_menu_template),
|
||||
GNOMEUIINFO_END
|
||||
};
|
||||
|
||||
@@ -1058,7 +1058,6 @@ gnc_register_create_status_bar (RegWindow *regData)
|
||||
return statusbar;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gnc_register_jump_to_blank (RegWindow *regData)
|
||||
{
|
||||
|
||||
86
src/register/formulacell.h
Normal file
86
src/register/formulacell.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/********************************************************************\
|
||||
* formulacell.h -- Formula entry/handling/display cell *
|
||||
* *
|
||||
* 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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/**
|
||||
* FILE:
|
||||
* formulacell.h
|
||||
*
|
||||
* FUNCTION:
|
||||
*
|
||||
* The FormulaCell object implements a cell which can contain a
|
||||
* mathematical formula involving some number of variables, defined by
|
||||
* the user. Any standard math functions [*, /, +, -, ()] are
|
||||
* supported, and any non-numeric, non-syntactic characters or
|
||||
* character strings are interpreted as variables; these character
|
||||
* strings may be enclosed by square brackets ([...]) if they contain
|
||||
* spaces.
|
||||
*
|
||||
* The FormulaCell will check for formula validity [paren-matching,
|
||||
* mainly].
|
||||
*
|
||||
* The FormulaCell...
|
||||
*
|
||||
* DOES...
|
||||
*
|
||||
* SHOULD DO...
|
||||
* . numeric-value detection
|
||||
* . paren-matching
|
||||
* . quick-fill on variables
|
||||
* . functions [special character strings which reference an external
|
||||
* function
|
||||
* . scheme
|
||||
*
|
||||
* HISTORY:
|
||||
* Copyright (c) 2001 Joshua Sled <jsled@asynchronous.org>
|
||||
**/
|
||||
|
||||
#ifndef __FORMULA_CELL_C__
|
||||
#define __FORMULA_CELL_C__
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "basiccell.h"
|
||||
#include "date.h"
|
||||
|
||||
|
||||
typedef struct _FormulaCell
|
||||
{
|
||||
BasicCell cell;
|
||||
} FormulaCell;
|
||||
|
||||
/* installs a callback to handle date recording */
|
||||
FormulaCell * xaccMallocFormulaCell (void);
|
||||
void xaccDestroyFormulaCell (FormulaCell *cell);
|
||||
|
||||
/* days are 1-31, mon is 1-12, year 1900 == 1900 */
|
||||
void xaccSetFormulaCellValue (FormulaCell *cell, int day, int mon, int year);
|
||||
void xaccSetFormulaCellValueSecs (FormulaCell *cell, time_t secs);
|
||||
void xaccSetFormulaCellValueSecsL (FormulaCell *cell, long long secs);
|
||||
|
||||
void xaccCommitFormulaCell (FormulaCell *cell);
|
||||
|
||||
void xaccFormulaCellGetDate (FormulaCell *cell, Timespec *ts);
|
||||
|
||||
#endif /* __FORMULA_CELL_C__ */
|
||||
|
||||
/* --------------- end of file ---------------------- */
|
||||
|
||||
@@ -80,6 +80,8 @@ struct _SplitRegisterBuffer
|
||||
CellBuffer sharesCell;
|
||||
CellBuffer mxfrmCell;
|
||||
CellBuffer notesCell;
|
||||
CellBuffer formCreditCell;
|
||||
CellBuffer formDebitCell;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@@ -110,6 +112,8 @@ static sample_string cell_sample_strings[] =
|
||||
{ N_("sample:999,999.000"), 7}, /* tshrbaln cell */
|
||||
{ N_("sample:999,999.000"), 7}, /* tbalance cell */
|
||||
{ N_("sample:Notes field sample text string"), 7}, /* notes cell */
|
||||
{ N_("sample:(x + 0.33 * y + (x+y) )"), 7 }, /* formula credit cell */
|
||||
{ N_("sample:(x + 0.33 * y + (x+y) )"), 7 }, /* formula debit cell */
|
||||
};
|
||||
|
||||
static CellAlignment cell_alignments[] =
|
||||
@@ -134,6 +138,8 @@ static CellAlignment cell_alignments[] =
|
||||
CELL_ALIGN_RIGHT, /* tshrbaln cell */
|
||||
CELL_ALIGN_RIGHT, /* tbalance cell */
|
||||
CELL_ALIGN_LEFT, /* notes cell */
|
||||
CELL_ALIGN_LEFT, /* formula credit cell */
|
||||
CELL_ALIGN_LEFT, /* formula debit cell */
|
||||
};
|
||||
|
||||
|
||||
@@ -145,7 +151,8 @@ xaccInitSplitRegister (SplitRegister *reg,
|
||||
TableView *view,
|
||||
VirtCellDataAllocator allocator,
|
||||
VirtCellDataDeallocator deallocator,
|
||||
VirtCellDataCopy copy);
|
||||
VirtCellDataCopy copy,
|
||||
gboolean templateMode);
|
||||
|
||||
|
||||
/* ============================================== */
|
||||
@@ -240,6 +247,7 @@ configAction (SplitRegister *reg)
|
||||
xaccAddComboCellMenuItem (reg->actionCell, _("Dist"));
|
||||
xaccAddComboCellMenuItem (reg->actionCell, _("Split"));
|
||||
break;
|
||||
|
||||
default:
|
||||
xaccAddComboCellMenuItem (reg->actionCell, _("Buy"));
|
||||
xaccAddComboCellMenuItem (reg->actionCell, _("Sell"));
|
||||
@@ -322,6 +330,8 @@ configLayout (SplitRegister *reg)
|
||||
CellBlock *curs;
|
||||
int i;
|
||||
|
||||
printf( "configLayout with type %d\n", reg->type );
|
||||
|
||||
/* fill things up with null cells */
|
||||
for (i = 0; i < reg->cursor_header->num_cols; i++)
|
||||
{
|
||||
@@ -369,8 +379,13 @@ configLayout (SplitRegister *reg)
|
||||
set_cell (reg, curs, DESC_CELL, 0, 2);
|
||||
set_cell (reg, curs, MXFRM_CELL, 0, 3);
|
||||
set_cell (reg, curs, RECN_CELL, 0, 4);
|
||||
if ( reg->template ) {
|
||||
set_cell( reg, curs, FDEBT_CELL, 0, 5);
|
||||
set_cell( reg, curs, FCRED_CELL, 0, 6);
|
||||
} else {
|
||||
set_cell (reg, curs, DEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, CRED_CELL, 0, 6);
|
||||
}
|
||||
set_cell (reg, curs, BALN_CELL, 0, 7);
|
||||
|
||||
curs = reg->cursor_ledger_double;
|
||||
@@ -397,8 +412,13 @@ configLayout (SplitRegister *reg)
|
||||
set_cell (reg, curs, MEMO_CELL, 0, 2);
|
||||
set_cell (reg, curs, XFRM_CELL, 0, 3);
|
||||
set_cell (reg, curs, RECN_CELL, 0, 4);
|
||||
if ( reg->template ) {
|
||||
set_cell( reg, curs, FDEBT_CELL, 0, 5);
|
||||
set_cell( reg, curs, FCRED_CELL, 0, 6);
|
||||
} else {
|
||||
set_cell (reg, curs, DEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, CRED_CELL, 0, 6);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -414,8 +434,13 @@ configLayout (SplitRegister *reg)
|
||||
set_cell (reg, curs, DESC_CELL, 0, 2);
|
||||
set_cell (reg, curs, MXFRM_CELL, 0, 3);
|
||||
set_cell (reg, curs, RECN_CELL, 0, 4);
|
||||
if ( reg->template ) {
|
||||
set_cell (reg, curs, FDEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, FCRED_CELL, 0, 6);
|
||||
} else {
|
||||
set_cell (reg, curs, DEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, CRED_CELL, 0, 6);
|
||||
}
|
||||
|
||||
curs = reg->cursor_ledger_double;
|
||||
copy_cursor_row (reg, curs, reg->cursor_ledger_single, 0);
|
||||
@@ -440,8 +465,13 @@ configLayout (SplitRegister *reg)
|
||||
set_cell (reg, curs, MEMO_CELL, 0, 2);
|
||||
set_cell (reg, curs, XFRM_CELL, 0, 3);
|
||||
set_cell (reg, curs, RECN_CELL, 0, 4);
|
||||
if ( reg->template ) {
|
||||
set_cell (reg, curs, FDEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, FCRED_CELL, 0, 6);
|
||||
} else {
|
||||
set_cell (reg, curs, DEBT_CELL, 0, 5);
|
||||
set_cell (reg, curs, CRED_CELL, 0, 6);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -540,7 +570,6 @@ configLayout (SplitRegister *reg)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
default:
|
||||
PERR ("unknown register type %d \n", reg->type);
|
||||
@@ -557,7 +586,8 @@ xaccMallocSplitRegister (SplitRegisterType type,
|
||||
TableView *view,
|
||||
VirtCellDataAllocator allocator,
|
||||
VirtCellDataDeallocator deallocator,
|
||||
VirtCellDataCopy copy)
|
||||
VirtCellDataCopy copy,
|
||||
gboolean templateMode)
|
||||
{
|
||||
SplitRegister * reg;
|
||||
|
||||
@@ -577,7 +607,8 @@ xaccMallocSplitRegister (SplitRegisterType type,
|
||||
view,
|
||||
allocator,
|
||||
deallocator,
|
||||
copy);
|
||||
copy,
|
||||
templateMode);
|
||||
|
||||
return reg;
|
||||
}
|
||||
@@ -655,7 +686,8 @@ xaccInitSplitRegister (SplitRegister *reg,
|
||||
TableView *view,
|
||||
VirtCellDataAllocator allocator,
|
||||
VirtCellDataDeallocator deallocator,
|
||||
VirtCellDataCopy copy)
|
||||
VirtCellDataCopy copy,
|
||||
gboolean templateMode)
|
||||
{
|
||||
Table * table;
|
||||
|
||||
@@ -666,6 +698,7 @@ xaccInitSplitRegister (SplitRegister *reg,
|
||||
reg->type = type;
|
||||
reg->style = style;
|
||||
reg->use_double_line = use_double_line;
|
||||
reg->template = templateMode;
|
||||
|
||||
/* --------------------------- */
|
||||
/* define the number of columns in the display, malloc the cursors */
|
||||
@@ -705,6 +738,8 @@ xaccInitSplitRegister (SplitRegister *reg,
|
||||
NEW (TSHRBALN, tshrbaln, Price);
|
||||
NEW (TBALN, tbalance, Price);
|
||||
NEW (NOTES, notes, QuickFill);
|
||||
NEW (FCRED, formCredit, QuickFill);
|
||||
NEW (FDEBT, formDebit, QuickFill);
|
||||
|
||||
/* --------------------------- */
|
||||
|
||||
@@ -761,6 +796,11 @@ xaccInitSplitRegister (SplitRegister *reg,
|
||||
/* the notes cell */
|
||||
xaccSetBasicCellBlankHelp (®->notesCell->cell,
|
||||
_("Enter notes for the transaction"));
|
||||
/* the formula cell */
|
||||
xaccSetBasicCellBlankHelp( ®->formCreditCell->cell,
|
||||
_("Enter credit formula for real transaction"));
|
||||
xaccSetBasicCellBlankHelp( ®->formDebitCell->cell,
|
||||
_("Enter debit formula for real transaction"));
|
||||
|
||||
/* Use 6 decimal places for prices */
|
||||
xaccSetPriceCellFraction (reg->priceCell, 1000000);
|
||||
@@ -918,6 +958,8 @@ xaccDestroySplitRegister (SplitRegister *reg)
|
||||
xaccDestroyPriceCell (reg->tshrbalnCell);
|
||||
xaccDestroyPriceCell (reg->tbalanceCell);
|
||||
xaccDestroyQuickFillCell (reg->notesCell);
|
||||
xaccDestroyQuickFillCell (reg->formCreditCell);
|
||||
xaccDestroyQuickFillCell (reg->formDebitCell);
|
||||
|
||||
reg->nullCell = NULL;
|
||||
reg->dateCell = NULL;
|
||||
@@ -940,6 +982,8 @@ xaccDestroySplitRegister (SplitRegister *reg)
|
||||
reg->tshrbalnCell = NULL;
|
||||
reg->tbalanceCell = NULL;
|
||||
reg->notesCell = NULL;
|
||||
reg->formCreditCell = NULL;
|
||||
reg->formDebitCell = NULL;
|
||||
|
||||
for (i = 0; i < CELL_TYPE_COUNT; i++)
|
||||
{
|
||||
@@ -987,6 +1031,9 @@ xaccSplitRegisterGetChangeFlag (SplitRegister *reg)
|
||||
changed |= MOD_MXFRM & reg->mxfrmCell->cell.changed;
|
||||
changed |= MOD_NOTES & reg->notesCell->cell.changed;
|
||||
|
||||
changed |= MOD_AMNT & reg->formCreditCell->cell.changed;
|
||||
changed |= MOD_AMNT & reg->formDebitCell->cell.changed;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -1010,6 +1057,9 @@ xaccSplitRegisterGetConditionalChangeFlag (SplitRegister *reg)
|
||||
changed |= MOD_MXFRM & reg->mxfrmCell->cell.conditionally_changed;
|
||||
changed |= MOD_NOTES & reg->notesCell->cell.conditionally_changed;
|
||||
|
||||
changed |= MOD_AMNT & reg->formCreditCell->cell.conditionally_changed;
|
||||
changed |= MOD_AMNT & reg->formDebitCell->cell.conditionally_changed;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -1031,6 +1081,8 @@ xaccSplitRegisterClearChangeFlag (SplitRegister *reg)
|
||||
reg->sharesCell->cell.changed = 0;
|
||||
reg->mxfrmCell->cell.changed = 0;
|
||||
reg->notesCell->cell.changed = 0;
|
||||
reg->formDebitCell->cell.changed = 0;
|
||||
reg->formCreditCell->cell.changed = 0;
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
@@ -1309,6 +1361,8 @@ xaccDestroySplitRegisterBuffer (SplitRegisterBuffer *srb)
|
||||
destroyCellBuffer(&srb->sharesCell);
|
||||
destroyCellBuffer(&srb->mxfrmCell);
|
||||
destroyCellBuffer(&srb->notesCell);
|
||||
destroyCellBuffer(&srb->formCreditCell);
|
||||
destroyCellBuffer(&srb->formDebitCell);
|
||||
|
||||
g_free(srb);
|
||||
}
|
||||
@@ -1349,6 +1403,8 @@ xaccSplitRegisterSaveCursor(SplitRegister *sr, SplitRegisterBuffer *srb)
|
||||
saveCell(&sr->sharesCell->cell, &srb->sharesCell);
|
||||
saveCell(&sr->mxfrmCell->cell, &srb->mxfrmCell);
|
||||
saveCell(&sr->notesCell->cell, &srb->notesCell);
|
||||
saveCell(&sr->formCreditCell->cell, &srb->formCreditCell);
|
||||
saveCell(&sr->formDebitCell->cell, &srb->formDebitCell);
|
||||
}
|
||||
|
||||
/* ============================================== */
|
||||
@@ -1412,6 +1468,8 @@ xaccSplitRegisterRestoreCursorChanged(SplitRegister *sr,
|
||||
restoreCellChanged(&sr->sharesCell->cell, &srb->sharesCell, cursor);
|
||||
restoreCellChanged(&sr->mxfrmCell->cell, &srb->mxfrmCell, cursor);
|
||||
restoreCellChanged(&sr->notesCell->cell, &srb->notesCell, cursor);
|
||||
restoreCellChanged(&sr->formCreditCell->cell, &srb->formCreditCell, cursor);
|
||||
restoreCellChanged(&sr->formDebitCell->cell, &srb->formDebitCell, cursor);
|
||||
}
|
||||
|
||||
/* keep in sync with CellType enum */
|
||||
@@ -1435,7 +1493,9 @@ static const char *cell_names[] =
|
||||
"trans-debit",
|
||||
"trans-share-balance",
|
||||
"trans-balance",
|
||||
"notes"
|
||||
"notes",
|
||||
"credit formula",
|
||||
"debit formula",
|
||||
};
|
||||
|
||||
const char *
|
||||
|
||||
@@ -75,6 +75,7 @@ typedef enum
|
||||
INCOME_LEDGER,
|
||||
PORTFOLIO_LEDGER,
|
||||
SEARCH_LEDGER,
|
||||
|
||||
NUM_REGISTER_TYPES
|
||||
} SplitRegisterType;
|
||||
|
||||
@@ -103,7 +104,9 @@ typedef enum
|
||||
TSHRBALN_CELL,
|
||||
TBALN_CELL,
|
||||
NOTES_CELL,
|
||||
CELL_TYPE_COUNT
|
||||
FCRED_CELL, // formula credit, used by the template ledger
|
||||
FDEBT_CELL, // formula debit, used by the template ledger
|
||||
CELL_TYPE_COUNT,
|
||||
} CellType;
|
||||
|
||||
/*
|
||||
@@ -139,6 +142,8 @@ typedef enum
|
||||
MOD_PRIC = 1 << 9,
|
||||
MOD_SHRS = 1 << 10,
|
||||
MOD_NOTES = 1 << 11,
|
||||
MOD_FCRED = 1 << 12,
|
||||
MOD_FDEBT = 1 << 13,
|
||||
MOD_ALL = 0xffff
|
||||
} CellModifiedFlags;
|
||||
|
||||
@@ -204,6 +209,9 @@ struct _SplitRegister
|
||||
PriceCell * tbalanceCell;
|
||||
QuickFillCell * notesCell;
|
||||
|
||||
QuickFillCell * formCreditCell;
|
||||
QuickFillCell * formDebitCell;
|
||||
|
||||
SplitRegisterType type;
|
||||
SplitRegisterStyle style;
|
||||
gboolean use_double_line;
|
||||
@@ -213,6 +221,17 @@ struct _SplitRegister
|
||||
BasicCell *header_cells[CELL_TYPE_COUNT];
|
||||
BasicCell *cells[CELL_TYPE_COUNT];
|
||||
|
||||
/**
|
||||
* A flag indicating a "template" register.
|
||||
**/
|
||||
gboolean template;
|
||||
|
||||
/**
|
||||
* The template account which the transactions in a template
|
||||
* splitregister will belong to.
|
||||
**/
|
||||
Account *templateAcct;
|
||||
|
||||
/* user_data allows users of this object to hang
|
||||
* private data onto it */
|
||||
gpointer user_data;
|
||||
@@ -236,7 +255,8 @@ xaccMallocSplitRegister (SplitRegisterType type,
|
||||
TableView *view,
|
||||
VirtCellDataAllocator allocator,
|
||||
VirtCellDataDeallocator deallocator,
|
||||
VirtCellDataCopy copy);
|
||||
VirtCellDataCopy copy,
|
||||
gboolean templateMode);
|
||||
|
||||
void xaccConfigSplitRegister (SplitRegister *reg,
|
||||
SplitRegisterType type,
|
||||
|
||||
@@ -66,6 +66,20 @@
|
||||
; (list "Extensions" "")
|
||||
; (lambda () (gnc:main-win-account-group-write win))))
|
||||
|
||||
|
||||
(define schedxact-editor-item
|
||||
(gnc:make-menu-item (N_ "SchedXact: Editor")
|
||||
(N_ "Editor of Scheduled Transactions")
|
||||
(list "Extensions" "")
|
||||
(lambda () (gnc:sx-editor)))
|
||||
)
|
||||
(define schedxact-slr-item
|
||||
(gnc:make-menu-item (N_ "SchedXact: Since Last Run")
|
||||
(N_ "since last run dialog")
|
||||
(list "Extensions" "")
|
||||
(lambda () (gnc:sx-since-last-run)))
|
||||
)
|
||||
|
||||
(define progress-item
|
||||
(gnc:make-menu-item (N_ "Test progress dialog")
|
||||
(N_ "Test progress dialog")
|
||||
@@ -91,7 +105,14 @@
|
||||
|
||||
(gnc:add-extension menu)
|
||||
; (gnc:add-extension export-item)
|
||||
(gnc:add-extension progress-item))
|
||||
|
||||
;; NOTE: this is the inverse order from how you may want them to
|
||||
;; appear in the menu [prepending to some list]...
|
||||
|
||||
(gnc:add-extension progress-item)
|
||||
(gnc:add-extension schedxact-slr-item)
|
||||
(gnc:add-extension schedxact-editor-item)
|
||||
)
|
||||
|
||||
(if (gnc:debugging?)
|
||||
(gnc:hook-add-dangler gnc:*ui-startup-hook*
|
||||
|
||||
Reference in New Issue
Block a user