Rob Browning's XML I/O Code.

Bill Gribble's commodity and numerics code and new qif importer druid.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3065 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas 2000-10-23 09:41:51 +00:00
parent dd68c0865f
commit e4e1453257
120 changed files with 21050 additions and 8288 deletions

246
ChangeLog
View File

@ -1,3 +1,249 @@
2000-10-23 Rob Browning <rlb@cs.utexas.edu>
* src/scm/main.scm:
(gnc:*batch-mode-things-to-do*): new var - keep track of startup bits.
(gnc:main): add --load processing for "things-to-do".
* src/scm/engine-utilities.scm:
(gnc:filename->account-group): new - likely temporary.
(gnc:call-with-account-data-from-file): new - likely temporary.
* src/scm/command-line.scm (gnc:*arg-defs*): add --load option in
addition to --evaluate.
* src/engine/sql/PostgresBackend.c: handle changes in the rest of
the code.
* src/engine/kvp_frame.c: change the datatype a little to pull the
union tag into the main struct. Also update the functions and
datatypes to more closely mirror glib types. i.e. lists are now
just GLists that must contain only kvp_value pointers. The kvp
docs have *not* been updated to reflect these changes (nor the
changes listed below).
(kvp_frame_set_slot): now setting a slot to a NULL value deletes
the slot. This is not in the docs yet.
(init_frame_body_if_needed): new function - only initialize the
guts of the kvp_frame if we need them. This helps in some
situations and should be free otherwise. All the other functions
should handle this properly now.
(kvp_value_new_binary_nc): new function - create a new binary
object using the pointer given directly.
(kvp_frame_for_each_slot): new function.
(kvp_value_compare): new function.
(kvp_frame_compare): new function.
* src/engine/kvp_frame.h: accomodate changes to kvp_frame.c.
* src/engine/guid.c:
(guid_compare): new function.
(guid_hash_to_guint): hash function from glib.
(guid_hash_table_new): new function.
(guid_g_hash_table_equal): new function.
* src/engine/guid.h: accomodate changes to guid.c.
* src/engine/date.c:
(timespec_equal): new function.
* src/engine/date.c: accomodate changes to date.c.
* src/engine/Transaction.c: update all functions to mark the
account's dirty flags when needed.
(xaccTransGetSlot): deleted - replaced by xaccTransGetSlots.
(xaccTransSetSlot): deleted - replaced by xaccTransGetSlots.
(xaccTransGetSlots): new function.
(xaccTransEqual): new function.
(DATE_CMP): don't use pointer to pointer args (unnecessary).
(xaccSplitDateOrder): now a total order - sort on guid if needed.
(xaccSplitOrder): deleted - unused.
(xaccTransOrder): now a total order - sort on guid if needed.
(xaccTransSetDocref): deleted.
(xaccTransGetDocref): deleted.
* src/engine/Transaction.h: accomodate changes to Transaction.c.
* src/engine/TransactionP.h: accomodate changes to Transaction.c.
* src/engine/Session.c:
(xaccSessionGetFileError): new function - migrate away from using
global for error status.
(xaccSessionBegin): change semantics - a begin does *not* load the
file automatically now. You must call xaccSessionLoad for that.
This is better, particularly in the SaveAs case when the load is
wasteful, and, until we fix the GUID code up so that loading the
same file twice doesn't cause a detonation, safer.
(xaccSessionBegin): change semantics - same as for
xaccSessionBegin.
(xaccSessionLoad): new function - loads the session data.
(xaccSessionSaveMayClobberData): new function - predicate.
(xaccSessionSave): change semantics - don't delete the file if
topgroup is NULL. This is too scary given all the other changes.
We can bring it back later if needed, but I'd probably rather see
an xaccSessionPurgeStorage, or similar.
* src/engine/Session.h: support changes to Session.c.
* src/engine/Makefile.am: handle new, deleted, and renamed files.
* src/engine/Group.c: handle vanished account id's, etc.
(xaccGroupEqual): new function.
(xaccGroupVisitUnvisitedTransactions): new function.
(xaccGroupForEachTransaction): new function.
(xaccGroupMapAccounts): new function (probably going away later).
(xaccGroupForEachAccountDeeply): ditto.
* src/engine/Group.h: handler changes to Acccount*'s and to Group.c.
* src/engine/GNCId.c:
(xaccGetAndResetEntityTable): new function - needed when you want
to load two files representing the same data for
comparison.
(xaccSetEntityTable): new function - needed when you want
to load two files representing the same data for
comparison.
* src/engine/GNCIdP.h: accomodate changes to GNCId.c
* src/engine/Account.c: many changes, removed some unused fields,
changed Account's to have a GList of splits rather than a NULL
terminated array of pointers - allowed optimizing several things
and made the code cleaner in spots.
(xaccAccountBeginEdit): remove defer argument - difficult to
handle with nesting - may add later if really needed. Change this
and
(xaccAccountCommitEdit): to handle nesting. Fix up all setter
routines to respect Begin/Commit, including ones for splits over
in Transaction.c.
(xaccInitAccount): Add/use sort_dirty and balance_dirty flags.
Change kvp_data to always be initialized (also changed kvp_frames
to be lighter weight when empty).
(xaccAccountEqual): new function.
(xaccSortSplits): new function.
(xaccAccountBringUpToDate): new function.
(xaccAccountGetSlot): deleted - replaced by xaccAccountGetSlots
(xaccAccountSetSlot): deleted - replaced by xaccAccountGetSlots
(xaccAccountGetSlots): new function - returns kvp_frame.
(xaccAccountGetID): deleted - accounts no longer have IDs.
(xaccAccountGetID): deleted - accounts no longer have flags.
(xaccAccountCheckDateOrder): renamed to xaccAccountFixSplitDateOrder.
(xaccCheckTransDateOrder): renamed to xaccTransFixSplitDateOrder.
(xaccAccountSetNotes): notes now stored in slot "notes".
(xaccAccountGetNotes): ditto.
(xaccAccountTypeEnumAsString): new function - required by text IO.
(xaccAccountStringToType): new function - required by text IO.
(xaccAccountSetPriceSrc): prices now stored in slot "old-price-source".
(xaccAccountGetPriceSrc): ditto.
(xaccAccountVisitUnvisitedTransactions): new function.
(xaccAccountForEachTransaction): new function.
* src/engine/Account.h: changes to accomodate above changes to
Account.c.
* src/engine/Account.h: changes to accomodate above changes to
Account.c.
* src/engine/io-gncxml-r.c: new xml format reader. This has a
semi-abstract incremental configurable low-ish memory XML tree
parser inside which should later be broken out into a separate
file.
* src/engine/io-gncxml-w.c: new xml format writer. This is pretty
straightforward, but due to limitations in libxml, has large
memory requirements. It has to build the entire XML tree in RAM
before it writes anything.
* src/engine/io-gncxml.h: new file - the current XML handling does
*not* have any transparent file compression. Expect that soon -
it doesn't make the performance any worse (thank goodness).
* src/engine/io-gncbin-r.c: renamed from src/engine/FileIO.c.
Only the reader is still active. All writing is as XML now.
* src/engine/io-gncbin.h: renamed from src/engine/FileIO.h.
* src/engine/FileIO.c: new file - now the meta-level file that has
functions that handle the various underlying file types. Any old
docref fields are stored in an "old-docref" slot and any old price
sources are stored in an "old-price-source" slot. Handle the fact
that account id's are gone.
* src/engine/FileIO.h: new file.
* make-gnucash-patch.in: ignore some more autogen files.
* src/FileDialog.c: update to handle new Session* semantics.
Saving and SavingAs are not the same anymore, session-wise. We
don't perform a pointless (and GUID dangerous) load before we
SaveAs.
* Many changes, not all of which will be documented right now.
This patch must get out. I'll come back and fix this up later.
The highlights are...
2000-10-16 Bill Gribble <grib@billgribble.com>
* Patch for new numeric representation, new commodity
representation, and rewritten QIF importer.
- numeric format: the engine's internal representation of values
changed from 'double' to 'gnc-numeric', an exact number format.
see src/doc/gnc-numeric.txt. This patch is step 1; the old
'double' engine API remains, but the names have been changed
from (for example) xaccSplitSetValue to DxaccSplitSetValue. The
D means deprecated. Will be gradually migrating the usage of
doubles to gnc-numeric throughout gnucash, eventually removing
the Dxacc API completely. ATM, there is no scheme support for
gnc-numeric, so I just left the Scheme API alone (old function
names still work, and work the same way).
- commodity representation: up to now, the engine has just used
strings to represent currencies. Now we use a struct
'gnc-commodity', which has more information about the
currency/stock/commodity than its name, including what exchange
it trades on and what the resolution of transactions is in
fractional units. When you read in an old gnucash file, you
will get a 'wizard' that will ask questions about the currencies
and stocks in your old file.
- QIF importer: I redid the GUI to be more of a wizard style.
This should get rid of a lot of people's problems using it since
it's more step-by-step oriented.
* src/scm/qif-import/qif-to-gnc.scm: set Reconcile correctly.
Also numerous other small changes.
* src/scm/qif-import/qif-parse.scm: handle 20000101 date formats
and MiscExpX category lines correctly.
* src/scm/qif-import/qif-file.scm: correctly handle ambiguous
date format by asking the right answer.
* src/scm/qif-import/qif-dialog-utils.scm: use the correct account
separator char for automatically created accounts
* src/scm/hooks.scm: added a file-opened-hook that gets run
any time a gnucash file is opened.
* src/engine/gnc-engine.{c,h}: new files for global engine
meta-operations. I mainly needed it to add a global list of known
'commodities' (currencies, stocks, etc), but there's now an
gnc-engine-init function called at startup with settable hooks.
* src/gnome/dialog-account.c: add "select" buttons for account
security and currency. Still need to make "smallest currency
unit" configurable per-account, but need to fix common-currency
problem first.
* src/gnome/dialog-find-transactions.c: use gnc_dateentry widget
* src/engine/Translog.c: warning! log format for numbers is
now "%Ld/%Ld", numerator/denominator.
* src/engine/Query.c: change date query functions to be more
useful. Start and end dates are optionally ignored, making it
possible to say "any date before.." or "any date after.."
2000-09-16 Dave Peticolas <dave@krondo.com>
* src/register/table-allgui.c: re-implement using gtables.

View File

@ -226,6 +226,13 @@ fi
LIBS="$LIBS -lm"
### --------------------------------------------------------------------------
### Gnome XML -- GNOME_XML_LIB is define by GNOME_XML_CHECK
GNOME_XML_CFLAGS=`$GNOME_CONFIG --cflags xml`
AC_SUBST(GNOME_XML_CFLAGS)
### --------------------------------------------------------------------------
GTKHTML_LIBS=`$GNOME_CONFIG --libs gtkhtml`
GTKHTML_CFLAGS=`$GNOME_CONFIG --cflags gtkhtml`

View File

@ -5,6 +5,7 @@
<!entity xaccnewacctwin system "xacc-newacctwin.sgml">
<!entity xaccadjbalwin system "xacc-adjbalwin.sgml">
<!entity xaccapar system "xacc-apar.sgml">
<!entity xacccommodity system "xacc-commodity.sgml">
<!entity xaccdepreciation system "xacc-depreciation.sgml">
<!entity xaccbalancereport system "xacc-balancereport.sgml">
<!entity xaccbalancesheet system "xacc-balancesheet.sgml">
@ -49,6 +50,7 @@
&xaccdepreciation;
&xaccbalancereport;
&xaccbalancesheet;
&xacccommodity;
&xacccurrencyhandling;
&xaccdoubleentry;
&xacceuro;

View File

@ -0,0 +1,46 @@
<ARTICLE ID="XACC-COMMODITY">
<ARTHEADER>
<TITLE>Creating a "commodity"</TITLE>
</ARTHEADER>
<PARA>Gnucash represents national currencies, stocks, mutual funds,
and all other tradable commodities using a unified framework. In
this dialog, you will specify the properties of a new commodity.
</PARA>
<para>The <emphasis>full name</emphasis> of the commodity is a recognizable
name such as "US Dollars" or "IBM Common Stock". </para>
<para>The <emphasis>symbol or abbreviation</emphasis> for the commodity is the
ticker symbol (for stocks), ISO currency symbol (for national
currencies), or other unique abbreviation for the commodity. If the
commodity is traded on any public exchange, it is important to use the
same identifier used on that exchange.
<para>The <emphasis>type</emphasis> of a commodity is the grouping or
namespace in which it exists. For example, national currencies are of
the ISO4217 type. ISO-4217 is an international standard which defines
unique three-letter symbols for each currency. Other types include
AMEX, NYSE, NASDAQ, and EUREX for stocks traded on those exchanges,
and FUND for mutual funds. If your commodity is not of one of these
types, you can create a new type by typing it in the box.</para>
<para>The commodity's <emphasis>code</emphasis> is any numeric or alphanumeric
code that is used to identify the commodity. The CUSIP code, for
example, is a unique identifying numeric string that is associated
with every stock, bond, mutual fund, and most kinds of tradable
options, futures, and commodities. This code is not required.</para>
<para>The <emphasis>fraction traded</emphasis> is the smallest tradable unit
of the commodity, expressed as a fraction of a single nominal unit.
For US Dollars, for example, the fraction traded is "1/100", because
bank balances and currency are counted to 1/100 of a dollar. This
value is used as a default accounting resolution for accounts
denominated in the security, but can be overridden if a particular
account's books need to be kept to a different resolution. For
example, stock ownership may be reckoned to 1/1000 of a share by some
brokerage houses, though actual transactions in the stock are in
integer numbers of shares (the fractional share ownership is an "on
paper" accounting trick of the brokerage house).</para>
</ARTICLE>

View File

@ -103,6 +103,8 @@ __DATA__
.#*
.deps
.libs
INSTALL
COPYING
Makefile
Makefile.in
Makefile.init
@ -114,6 +116,7 @@ conf.h
config.cache
config.guess
config.h
config.h.in
config.log
config.status
config.sub
@ -130,6 +133,7 @@ gnucash-engine-perl5_wrap_int.c
gnucash.engine.i
gnucash.pm
gnucash.pot
install-sh
intl/libintl.h
intl/po2tbl.sed
lib/finance-quote/blib

View File

@ -7,7 +7,6 @@ src/gnome/dialog-account.c
src/gnome/dialog-account-picker.c
src/gnome/dialog-fincalc.c
src/gnome/dialog-progress.c
src/gnome/dialog-qif-import.c
src/gnome/dialog-totd.c
src/gnome/glade-gnc-dialogs.c
src/gnome/print-session.c

View File

@ -22,17 +22,16 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "gnc-commodity.h"
#include "EuroUtils.h"
/* local structs */
typedef struct _gnc_euro_rate_struct
{
typedef struct _gnc_euro_rate_struct {
const char *currency;
double rate;
}
gnc_euro_rate_struct;
} gnc_euro_rate_struct;
/* This array MUST be sorted ! */
static gnc_euro_rate_struct _gnc_euro_rate_[] =
@ -64,33 +63,35 @@ static gnc_euro_rate_struct _gnc_euro_rate_[] =
{ "SCH", 13.7603 } /* austrian schilling */
};
static int
_gnc_euro_rate_compare_(const void *euro_rate_struct1,
const void *euro_rate_struct2)
static int
_gnc_euro_rate_compare_(const void * key,
const void * value)
{
return (strcasecmp(((const gnc_euro_rate_struct *)euro_rate_struct1)->currency,
((const gnc_euro_rate_struct *)euro_rate_struct2)->currency));
const gnc_commodity * curr = key;
const gnc_euro_rate_struct * euro = value;
if(!key || !value) return -1;
return strcasecmp(gnc_commodity_get_mnemonic(curr), euro->currency);
}
/* ------------------------------------------------------ */
int
gnc_is_euro_currency(const char *currency)
{
gnc_euro_rate_struct test_currency;
int
gnc_is_euro_currency(const gnc_commodity * currency) {
gnc_euro_rate_struct *result;
test_currency.currency = currency;
result = (gnc_euro_rate_struct *)bsearch(&test_currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL)
{
result = (gnc_euro_rate_struct *)
bsearch(currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct),
sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL) {
return 0;
}
else
{
else {
return 1;
}
}
@ -98,45 +99,42 @@ gnc_is_euro_currency(const char *currency)
/* ------------------------------------------------------ */
double
gnc_convert_to_euro(const char *currency, double value)
{
gnc_euro_rate_struct test_currency;
gnc_convert_to_euro(const gnc_commodity * currency, double value) {
gnc_euro_rate_struct *result;
test_currency.currency = currency;
result = (gnc_euro_rate_struct *)bsearch(&test_currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL)
{
result = (gnc_euro_rate_struct *)
bsearch(currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct),
sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL) {
return 0.0;
}
else
{
return (floor(((value / result->rate) * 100.0) + 0.5) / 100.0); /* round to 2 decimal places */
else {
/* round to 2 decimal places */
return (floor(((value / result->rate) * 100.0) + 0.5) / 100.0);
}
}
/* ------------------------------------------------------ */
double
gnc_convert_from_euro(const char *currency, double value)
{
gnc_euro_rate_struct test_currency;
gnc_euro_rate_struct *result;
test_currency.currency = currency;
result = (gnc_euro_rate_struct *)bsearch(&test_currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct), sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL)
{
double
gnc_convert_from_euro(const gnc_commodity * currency, double value) {
gnc_euro_rate_struct * result;
result = (gnc_euro_rate_struct *)
bsearch(currency, _gnc_euro_rate_,
sizeof(_gnc_euro_rate_)/sizeof(gnc_euro_rate_struct),
sizeof(gnc_euro_rate_struct),
_gnc_euro_rate_compare_);
if(result == NULL) {
return 0.0;
}
else
{
else {
return (value * result->rate);
}
}

View File

@ -22,9 +22,11 @@
#ifndef __EURO_UTILS_H__
#define __EURO_UTILS_H__
int gnc_is_euro_currency(const char *currency);
double gnc_convert_to_euro(const char *currency, double value);
double gnc_convert_from_euro(const char *currency, double value);
#include "gnc-commodity.h"
int gnc_is_euro_currency(const gnc_commodity * currency);
double gnc_convert_to_euro(const gnc_commodity * currency, double value);
double gnc_convert_from_euro(const gnc_commodity * currency, double value);
#endif /* __EURO_UTILS_H__ */

View File

@ -21,6 +21,7 @@
#include <string.h>
#include <glib.h>
#include <guile/gh.h>
#include "top-level.h"
@ -37,7 +38,7 @@
#include "file-history.h"
/* This static indicates the debugging module that this .o belongs to. */
/* static short module = MOD_GUI; */
static short module = MOD_GUI;
/** GLOBALS *********************************************************/
static Session *current_session = NULL;
@ -54,14 +55,20 @@ file_not_found_msg (void)
/* ======================================================== */
static gboolean
show_file_error (int io_error, char *newfile)
show_file_error (GNCFileIOError io_error, char *newfile)
{
gboolean uh_oh = FALSE;
char *buf = NULL;
switch (io_error)
{
case ERR_FILEIO_NO_ERROR:
case ERR_FILEIO_NONE:
break;
case ERR_FILEIO_MISC:
buf = _("Something went wrong during file IO,\n"
"but I'm not sure what.");
if (!gnc_verify_dialog (buf, TRUE))
uh_oh = TRUE;
break;
case ERR_FILEIO_FILE_NOT_FOUND:
buf = g_strdup_printf (file_not_found_msg(), newfile);
@ -94,6 +101,7 @@ show_file_error (int io_error, char *newfile)
uh_oh = TRUE;
break;
default:
PERR("FIXME: Unhandled FileIO error in show_file_error.");
break;
}
@ -129,7 +137,6 @@ show_session_error(Session *session, char *newfile)
}
g_free(buf);
return uh_oh;
}
@ -246,7 +253,6 @@ gncPostFileOpen (const char * filename)
Session *newsess;
AccountGroup *oldgrp;
gboolean uh_oh = FALSE;
int io_error;
AccountGroup *newgrp;
char * newfile;
@ -274,7 +280,12 @@ gncPostFileOpen (const char * filename)
* switchover is not something we want to keep in a journal. */
gnc_set_busy_cursor(NULL);
xaccLogDisable();
newgrp = xaccSessionBeginFile (newsess, newfile, gncLockFailHandler);
newgrp = NULL;
if(xaccSessionBeginFile(newsess, newfile, gncLockFailHandler)) {
if(xaccSessionLoad(newsess)) {
newgrp = xaccSessionGetGroup(newsess);
}
}
xaccLogEnable();
gnc_unset_busy_cursor(NULL);
@ -283,9 +294,9 @@ gncPostFileOpen (const char * filename)
if (!uh_oh)
{
GNCFileIOError io_err = xaccSessionGetFileError(newsess);
/* check for i/o error, put up appropriate error message */
io_error = xaccGetFileIOError();
uh_oh = show_file_error (io_error, newfile);
uh_oh = show_file_error(io_err, newfile);
if (uh_oh)
{
xaccFreeAccountGroup (newgrp);
@ -294,7 +305,7 @@ gncPostFileOpen (const char * filename)
/* Umm, came up empty-handed, i.e. the file was not found. */
/* This is almost certainly not what the user wanted. */
if (!uh_oh && !newgrp && !io_error)
if (!uh_oh && !newgrp && (io_err == ERR_FILEIO_NONE))
{
char *buf = g_strdup_printf (file_not_found_msg(), newfile);
gnc_error_dialog (buf);
@ -341,6 +352,19 @@ gncPostFileOpen (const char * filename)
xaccLogEnable();
free (newfile);
/* run a file-opened hook. For now, the main thing it will do
* is notice if legacy currencies are being imported. */
{
SCM run_danglers = gh_eval_str("gnc:hook-run-danglers");
SCM hook = gh_eval_str("gnc:*file-opened-hook*");
SCM filename;
if(newfile) {
filename = gh_str02scm(newfile);
gh_call2(run_danglers, hook, filename);
}
}
}
/* ======================================================== */
@ -379,15 +403,6 @@ gncFileOpenFile (const char * newfile)
gncPostFileOpen (newfile);
}
/* ======================================================== */
void
gncFileQIFImport (void)
{
/* pop up the QIF File Import dialog box */
gnc_ui_qif_import_dialog_make();
}
/* ======================================================== */
static int been_here_before = 0;
@ -396,7 +411,8 @@ gncFileSave (void)
{
AccountGroup *newgrp = NULL;
char * newfile;
int io_error, norr, uh_oh = 0;
GNCFileIOError io_err;
int norr, uh_oh = 0;
/* hack alert -- Somehow make sure all in-progress edits get committed! */
@ -414,8 +430,8 @@ gncFileSave (void)
xaccSessionSave (current_session);
gnc_unset_busy_cursor(NULL);
/* in theory, no error should have occured, but just in case,
* we're gonna check and handle ... */
/* Make sure everything's OK - disk could be full, file could have
become read-only etc. */
norr = xaccSessionGetError (current_session);
if (norr)
{
@ -441,11 +457,11 @@ gncFileSave (void)
/* check for i/o error, put up appropriate error message.
* NOTE: the file-writing routines never set the file io
* error code, so this seems to be unneccesary. */
io_error = xaccGetFileIOError();
io_err = xaccSessionGetFileError(current_session);
newfile = xaccSessionGetFilePath(current_session);
gnc_history_add_file(newfile);
uh_oh = show_file_error (io_error, newfile);
uh_oh = show_file_error (io_err, newfile);
if (uh_oh)
{
xaccFreeAccountGroup (newgrp);
@ -467,9 +483,7 @@ gncFileSaveAs (void)
AccountGroup *oldgrp;
const char *filename;
char *newfile;
AccountGroup *newgrp;
char * oldfile;
int io_error;
gboolean uh_oh = FALSE;
filename = fileBox(SAVE_STR, "*.gnc");
@ -488,15 +502,13 @@ gncFileSaveAs (void)
return;
}
oldfile = xaccSessionGetFilePath (current_session);
if (oldfile && !strcmp (oldfile, newfile))
{
if (oldfile && (strcmp(oldfile, newfile) == 0)) {
free (newfile);
gncFileSave ();
return;
}
/* -------------- BEGIN CORE SESSION CODE ------------- */
/* -- this code identical in FileOpen and FileSaveAs -- */
/* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
oldgrp = xaccSessionGetGroup (current_session);
/* if session not yet started ... */
if (!oldgrp) oldgrp = topgroup;
@ -508,28 +520,16 @@ gncFileSaveAs (void)
* edit; the mass deletetion of accounts and transactions during
* switchover is not something we want to keep in a journal. */
xaccLogDisable();
newgrp = xaccSessionBeginFile (newsess, newfile, gncLockFailHandler);
xaccSessionBeginFile(newsess, newfile, gncLockFailHandler);
xaccLogEnable();
/* check for session errors (e.g. file locked by another user) */
uh_oh = show_session_error (newsess, newfile);
if (!uh_oh)
{
/* check for i/o error, put up appropriate error message */
io_error = xaccGetFileIOError();
uh_oh = show_file_error (io_error, newfile);
if (uh_oh)
{
xaccFreeAccountGroup (newgrp);
newgrp = NULL;
}
}
/* No check for file errors since we didn't read a file... */
/* going down -- abandon ship */
if (uh_oh)
{
xaccSessionEnd (newsess);
if (uh_oh) {
xaccSessionDestroy (newsess);
/* well, no matter what, I think its a good idea to have
@ -538,27 +538,22 @@ gncFileSaveAs (void)
* reason, we don't want to leave them high & dry without a topgroup,
* because if user continues, then bad things will happen ...
*/
if (NULL == topgroup)
{
if(NULL == topgroup) {
topgroup = xaccMallocAccountGroup();
}
free (newfile);
gnc_refresh_main_window();
return;
}
/* if we got to here, then we've successfully gotten a new session */
/* close up the old file session (if any) */
xaccSessionEnd (current_session);
xaccSessionDestroy (current_session);
current_session = newsess;
/* --------------- END CORE SESSION CODE -------------- */
/* oops ... file already exists ... ask user what to do... */
if (newgrp)
{
if(xaccSessionSaveMayClobberData(newsess)) {
char *tmpmsg;
gboolean result;
@ -576,7 +571,6 @@ gncFileSaveAs (void)
* decides it was all a big mistake. */
xaccSessionSetGroup (newsess, NULL);
/* xaccLogDisable(); no don't disable, keep logging on */
xaccFreeAccountGroup (newgrp);
}
/* OK, save the data to the file ... */

View File

@ -452,10 +452,10 @@ xaccLedgerDisplayRefresh (xaccLedgerDisplay *regData)
/* provide some convenience data for the the GUI window.
* If the GUI wants to display yet other stuff, it's on its own. */
regData->balance = xaccAccountGetBalance (regData->leader);
regData->clearedBalance = xaccAccountGetClearedBalance (regData->leader);
regData->balance = DxaccAccountGetBalance (regData->leader);
regData->clearedBalance = DxaccAccountGetClearedBalance (regData->leader);
regData->reconciledBalance =
xaccAccountGetReconciledBalance(regData->leader);
DxaccAccountGetReconciledBalance(regData->leader);
/* OK, now tell this specific GUI window to redraw itself ... */
if (regData->redraw)

View File

@ -100,12 +100,14 @@
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <glib.h>
#include <guile/gh.h>
#include "top-level.h"
#include "Account.h"
#include "ui-callbacks.h"
#include "SplitLedger.h"
#include "MultiLedger.h"
@ -428,13 +430,13 @@ gnc_find_split_in_trans_by_memo(Transaction *trans, const char *memo,
{
Split *split = xaccTransGetSplit(trans, i);
if (unit_price && (xaccSplitGetSharePrice(split) != 1.0))
if (unit_price && (DxaccSplitGetSharePrice(split) != 1.0))
continue;
if (safe_strcmp(memo, xaccSplitGetMemo(split)) == 0)
{
Account *account = xaccSplitGetAccount(split);
const char *currency, *security;
const gnc_commodity *currency, *security;
if (account == NULL)
return split;
@ -458,39 +460,21 @@ gnc_find_split_in_trans_by_memo(Transaction *trans, const char *memo,
* is a transaction used for currency checking. */
static Split *
gnc_find_split_in_account_by_memo(Account *account, const char *memo,
Transaction *dest_trans, gboolean unit_price)
{
Split **splits;
Split **orig;
Transaction *dest_trans, gboolean unit_price) {
GList *slp;
if (account == NULL)
return NULL;
if (account == NULL) return NULL;
splits = xaccAccountGetSplitList(account);
if ((splits == NULL) || (*splits == NULL))
return NULL;
for(slp = g_list_last(xaccAccountGetSplitList(account));
slp;
slp = slp->prev) {
Split *split = (Split *) slp->data;
Transaction *trans = xaccSplitGetParent(split);
orig = splits;
while (*splits != NULL)
splits++;
do
{
Transaction *trans;
Split *split;
splits--;
trans = xaccSplitGetParent(*splits);
split = gnc_find_split_in_trans_by_memo(trans, memo, dest_trans,
unit_price);
if (split != NULL)
return split;
} while (splits != orig);
split = gnc_find_split_in_trans_by_memo(trans, memo, dest_trans, unit_price);
if (split != NULL) return split;
}
return NULL;
}
@ -499,36 +483,20 @@ gnc_find_split_in_account_by_memo(Account *account, const char *memo,
* in registers with a default leading account. The dest_trans is a
* transaction used for currency checking. */
static Transaction *
gnc_find_trans_in_account_by_desc(Account *account, const char *description)
{
Split **splits;
Split **orig;
gnc_find_trans_in_account_by_desc(Account *account, const char *description) {
GList *slp;
if (account == NULL)
return NULL;
if (account == NULL) return NULL;
splits = xaccAccountGetSplitList(account);
if ((splits == NULL) || (*splits == NULL))
return NULL;
for(slp = g_list_last(xaccAccountGetSplitList(account));
slp;
slp = slp->prev) {
Split *split = (Split *) slp->data;
Transaction *trans = xaccSplitGetParent(split);
orig = splits;
while (*splits != NULL)
splits++;
do
{
Transaction *trans;
splits--;
trans = xaccSplitGetParent(*splits);
if (safe_strcmp(description, xaccTransGetDescription(trans)) == 0)
if(safe_strcmp(description, xaccTransGetDescription(trans)) == 0)
return trans;
} while (splits != orig);
}
return NULL;
}
@ -904,7 +872,7 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
g_list_free(refresh_accounts);
/* now move to the non-empty amount column */
amount = xaccSplitGetShareAmount (blank_split);
amount = DxaccSplitGetShareAmount (blank_split);
cell_type = (amount >= 0) ? DEBT_CELL : CRED_CELL;
if (xaccSplitRegisterGetCurrentCellLoc (reg, cell_type, &new_virt_loc))
@ -971,7 +939,7 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
xaccSetComboCellValue (reg->xfrmCell, fullname);
xaccBasicCellSetChanged(&(reg->xfrmCell->cell), TRUE);
amount = xaccSplitGetValue (auto_split);
amount = DxaccSplitGetValue (auto_split);
xaccSetDebCredCellValue (reg->debitCell, reg->creditCell, amount);
xaccBasicCellSetChanged (&(reg->debitCell->cell), TRUE);
@ -981,7 +949,7 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
gnc_table_refresh_gui (reg->table);
/* now move to the non-empty amount column */
amount = xaccSplitGetShareAmount (auto_split);
amount = DxaccSplitGetShareAmount (auto_split);
cell_type = (amount < 0) ? CRED_CELL : DEBT_CELL;
if (xaccSplitRegisterGetCurrentCellLoc (reg, cell_type, &new_virt_loc))
@ -1102,10 +1070,10 @@ LedgerTraverse (Table *table,
if (xaccSRGetTransSplitVirtLoc (reg, new_trans, trans_split,
new_split, &vcell_loc))
virt_loc.vcell_loc = vcell_loc;
gnc_table_find_close_valid_cell (table, &virt_loc,
info->exact_traversal);
*p_new_virt_loc = virt_loc;
}
@ -1186,6 +1154,7 @@ xaccSRGetTrans (SplitRegister *reg, VirtualCellLocation vcell_loc)
return NULL;
split = sr_get_split (reg, vcell_loc);
if (split != NULL)
return xaccSplitGetParent(split);
@ -1373,7 +1342,7 @@ xaccSRGetSplitAmountVirtLoc (SplitRegister *reg, Split *split,
cursor_class = xaccSplitRegisterGetCursorClass (reg, v_loc.vcell_loc);
value = xaccSplitGetValue (split);
value = DxaccSplitGetValue (split);
if (DEQ (value, 0.0))
value = 0.0;
@ -1388,7 +1357,7 @@ xaccSRGetSplitAmountVirtLoc (SplitRegister *reg, Split *split,
default:
return FALSE;
}
if (!xaccSplitRegisterGetCellLoc (reg, cell_type, v_loc.vcell_loc, &v_loc))
return FALSE;
@ -1885,7 +1854,7 @@ xaccSRDeleteCurrentSplit (SplitRegister *reg)
account = xaccSplitGetAccount(split);
xaccTransBeginEdit(trans, TRUE);
xaccAccountBeginEdit(account, TRUE);
xaccAccountBeginEdit(account);
xaccSplitDestroy(split);
xaccAccountCommitEdit(account);
xaccTransCommitEdit(trans);
@ -2513,8 +2482,8 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
if ((new_acc != NULL) && (old_acc != new_acc))
{
const char *currency = NULL;
const char *security = NULL;
const gnc_commodity * currency = NULL;
const gnc_commodity * security = NULL;
currency = xaccAccountGetCurrency(new_acc);
currency = xaccTransIsCommonExclSCurrency(trans, currency, split);
@ -2562,12 +2531,12 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
if (!other_split) {
other_split = xaccTransGetSplit (trans, 1);
if (!other_split) {
double amt = xaccSplitGetShareAmount (split);
double prc = xaccSplitGetSharePrice (split);
double amt = DxaccSplitGetShareAmount (split);
double prc = DxaccSplitGetSharePrice (split);
other_split = xaccMallocSplit ();
xaccSplitSetSharePriceAndAmount (other_split, prc, -amt);
DxaccSplitSetSharePriceAndAmount (other_split, prc, -amt);
xaccTransAppendSplit (trans, other_split);
}
@ -2584,8 +2553,8 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
if ((new_acc != NULL) && (old_acc != new_acc))
{
const char *currency = NULL;
const char *security = NULL;
const gnc_commodity * currency = NULL;
const gnc_commodity * security = NULL;
currency = xaccAccountGetCurrency(new_acc);
currency = xaccTransIsCommonExclSCurrency(trans,
@ -2627,12 +2596,12 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
if (MOD_SHRS & changed)
amount = xaccGetPriceCellValue(reg->sharesCell);
else
amount = xaccSplitGetShareAmount(split);
amount = DxaccSplitGetShareAmount(split);
if (MOD_PRIC & changed)
price = xaccGetPriceCellValue(reg->priceCell);
else
price = xaccSplitGetSharePrice(split);
price = DxaccSplitGetSharePrice(split);
if (MOD_AMNT & changed) {
double credit = xaccGetPriceCellValue(reg->creditCell);
@ -2640,7 +2609,7 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
value = debit - credit;
}
else
value = xaccSplitGetValue(split);
value = DxaccSplitGetValue(split);
if (!DEQEPS(value, price * amount, 1.0e-15)) {
int i;
@ -2727,7 +2696,7 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
DEBUG ("MOD_SHRS: %f\n", amount);
xaccSplitSetShareAmount (split, amount);
DxaccSplitSetShareAmount (split, amount);
}
if (MOD_PRIC & changed) {
@ -2737,7 +2706,7 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
DEBUG ("MOD_PRIC: %f\n", price);
xaccSplitSetSharePrice (split, price);
DxaccSplitSetSharePrice (split, price);
}
/* The AMNT and NAMNT updates only differ by sign. Basically,
@ -2755,9 +2724,9 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
DEBUG ("MOD_AMNT: %f\n", new_amount);
xaccSplitSetValue (split, new_amount);
DxaccSplitSetValue (split, new_amount);
}
return refresh_accounts;
}
@ -2820,9 +2789,9 @@ xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
if (split == blank_split)
return "";
balance = xaccSplitGetShareBalance (split);
balance = DxaccSplitGetShareBalance (split);
return xaccPrintAmount (balance, PRTSEP | PRTSHR, NULL);
return DxaccPrintAmount (balance, PRTSEP | PRTSHR, NULL);
}
break;
@ -2837,7 +2806,7 @@ xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
/* If the reverse_balance callback is present use that.
* Otherwise, reverse income and expense by default. */
balance = xaccSplitGetBalance (split);
balance = DxaccSplitGetBalance (split);
if (reverse_balance != NULL)
{
Account *account;
@ -2853,7 +2822,7 @@ xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
(EXPENSE_REGISTER == reg->type))
balance = -balance;
return xaccPrintAmount (balance, PRTSEP, NULL);
return DxaccPrintAmount (balance, PRTSEP, NULL);
}
break;
@ -2888,7 +2857,7 @@ xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
{
double amount;
amount = xaccSplitGetValue (split);
amount = DxaccSplitGetValue (split);
if (DEQ (amount, 0.0))
return "";
@ -2900,28 +2869,28 @@ xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
amount = DABS (amount);
return xaccPrintAmount (amount, PRTSEP, NULL);
return DxaccPrintAmount (amount, PRTSEP, NULL);
}
case PRIC_CELL:
{
double price;
price = xaccSplitGetSharePrice (split);
price = DxaccSplitGetSharePrice (split);
return xaccPrintAmount (price, PRTSEP | PRTCUR, NULL);
return DxaccPrintAmount (price, PRTSEP | PRTCUR, NULL);
}
case SHRS_CELL:
{
double shares;
shares = xaccSplitGetShareAmount (split);
shares = DxaccSplitGetShareAmount (split);
if (DEQ (shares, 0.0))
return "";
return xaccPrintAmount (shares, PRTSEP | PRTSHR, NULL);
return DxaccPrintAmount (shares, PRTSEP | PRTSHR, NULL);
}
case MXFRM_CELL:
@ -2982,7 +2951,7 @@ xaccSRGetFGColorHandler (gpointer vcell_data, short _cell_type,
{
double balance;
balance = xaccSplitGetShareBalance (split);
balance = DxaccSplitGetShareBalance (split);
if (DEQ (balance, 0.0))
balance = 0.0;
@ -2999,7 +2968,7 @@ xaccSRGetFGColorHandler (gpointer vcell_data, short _cell_type,
/* If the reverse_balance callback is present use that.
* Otherwise, reverse income and expense by default. */
balance = xaccSplitGetBalance (split);
balance = DxaccSplitGetBalance (split);
if (reverse_balance != NULL)
{
Account *account;
@ -3635,10 +3604,10 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
/* walk account tree recursively, pulling out all the names */
static void
LoadXferCell (ComboCell *cell,
AccountGroup *grp,
const char *base_currency,
const char *base_security)
LoadXferCell (ComboCell * cell,
AccountGroup * grp,
const gnc_commodity * base_currency,
const gnc_commodity * base_security)
{
gboolean load_everything;
Account * acc;
@ -3659,20 +3628,19 @@ LoadXferCell (ComboCell *cell,
n = 0;
acc = xaccGroupGetAccount (grp, n);
while (acc) {
const char *curr, *secu;
const gnc_commodity * curr, * secu;
curr = xaccAccountGetCurrency (acc);
secu = xaccAccountGetSecurity (acc);
if (secu && (0x0 == secu[0])) secu = NULL;
DEBUG ("curr=%s secu=%s acct=%s\n",
DEBUG ("curr=%p secu=%p acct=%s\n",
curr, secu, xaccAccountGetName (acc));
if ( load_everything ||
(!safe_strcmp(curr,base_currency)) ||
(!safe_strcmp(curr,base_security)) ||
(secu && (!safe_strcmp(secu,base_currency))) ||
(secu && (!safe_strcmp(secu,base_security))) )
(gnc_commodity_equiv(curr,base_currency)) ||
(gnc_commodity_equiv(curr,base_security)) ||
(secu && (gnc_commodity_equiv(secu,base_currency))) ||
(secu && (gnc_commodity_equiv(secu,base_security))) )
{
name = xaccAccountGetFullName (acc, account_separator);
if (name != NULL)
@ -3697,14 +3665,11 @@ xaccLoadXferCell (ComboCell *cell,
AccountGroup *grp,
Account *base_account)
{
const char *curr, *secu;
const gnc_commodity * curr, * secu;
curr = xaccAccountGetCurrency (base_account);
secu = xaccAccountGetSecurity (base_account);
if ((secu != NULL) && (secu[0] == 0))
secu = NULL;
xaccClearComboCellMenu (cell);
xaccAddComboCellMenuItem (cell, "");
LoadXferCell (cell, grp, curr, secu);

10
src/doc/gnc-commodity.txt Normal file
View File

@ -0,0 +1,10 @@
README.gnc-commodity
Bill Gribble <grib@gnumatic.com>
2 Aug 2000
gnc-commodity : a representation of currencies, stocks, and other
tradable commodities.

280
src/doc/gnc-numeric.txt Normal file
View File

@ -0,0 +1,280 @@
API documentation for gnc-numeric
---------------------------------
The gnc_numeric API provides data types and functions for manipulating
exact numeric quantities. gnc_numeric was developed to represent and
operate on exact financial quantities in gnucash, but it is
(hopefully) suitable for use in most places an exact numeric
representation for non-integer numbers is needed.
gnc_numeric represents numbers in a rational form, with a 64-bit 'long
long' integer as numerator and denominator. If more precision is
needed, or a higher-precision representation of irrational numbers, or
a wider dynamic range, a floating point format may be appropriate.
There are reasonable rational approximations to common irrational
constants [1], but the transcendental functions have not been
implemented for gnc_numeric objects.
1. Standard arguments
It is useful to specify a denominator in cases where it is known that
the output value is of constrained precision. For example, monetary
transactions must be executed in an integer number of the "smallest
currency unit" of the transaction. In US Dollars, the smallest
currency unit is the cent, and all monetary transactions must be done
in units of cents. Therefore, any fractional cents in a computed
price must be rounded away.
Most of the gnc_numeric arithmetic functions take two arguments in
addition to their numeric args: 'denom', which is the denominator to
use in the output gnc_numeric object, and 'how', which describes how
the arithmetic result is to be converted to that denominator. This
combination of output denominator and rounding policy allows the
results of financial and other exact computations to be properly
rounded to the appropriate units.
Valid values for 'denom' are:
n (positive int) Use the number 'n' as the denominator of the
output value.
GNC_DENOM_RECIPROCAL( n ) Use the value '1/n' as the denominator of
the output value.
GNC_DENOM_AUTO Compute an appropriate denominator
automatically. Flags in the 'how'
argument will specify how to compute the
denominator.
Valid values for 'how' are bitwise combinations of zero or one
"rounding instructions" with zero or one "denominator types".
Rounding instructions control how fractional parts in the specified
denominator affect the result. For example, if a computed result is
"3/4" but the specified denominator for the return value is 2, should
the return value be "1/2" or "2/2"?
Possible rounding instructions are:
GNC_RND_FLOOR : round toward -infinity
GNC_RND_CEIL : round toward +infinity
GNC_RND_TRUNC : truncate fractions (round toward zero)
GNC_RND_PROMOTE : promote fractions (round away from zero)
GNC_RND_ROUND : use unbiased ("banker's") rounding. This rounds
to the nearest integer, and to the nearest even
integer when there are two equidistant nearest
integers.
GNC_RND_ROUND_HALF_UP : round to the nearest integer, rounding away
from zero when there are two equidistant nearest
integers.
GNC_RND_ROUND_HALF_DOWN : round to the nearest integer, rounding toward
zero when there are two equidistant nearest
integers.
GNC_RND_NEVER : never round at all, and signal an error if there is a
fractional result in a computation.
The denominator type specifies how to compute a denominator if
GNC_DENOM_AUTO is specified as the 'denom'. Valid denominator types
are:
GNC_DENOM_EXACT : Use any denominator which gives an exactly correct
ratio of numerator to denominator. Use EXACT when
you do not wish to lose any information in the result
but also do not want to spend any time finding the
"best" denominator.
GNC_DENOM_REDUCE : Reduce the result value by common factor elimination,
using the smallest possible value for the denominator
that keeps the correct ratio. The numerator and
denominator of the result are relatively prime.
This can be computationally expensive for large
fractions.
GNC_DENOM_LCD : Find the least common multiple of the arguments'
denominators and use that as the denominator of the
result.
GNC_DENOM_FIXED : All arguments are required to have the same denominator,
that denominator is to be used in the output, and
an error is to be signaled if any argument has a
different denominator.
To use traditional rational-number operational semantics (all results
are exact and are reduced to relatively-prime fractions) pass the
argument GNC_DENOM_AUTO as 'denom' and GNC_DENOM_REDUCE | GNC_RND_NEVER
as 'how'.
To enforce strict financial semantics (such that all operands must
have the same denominator as each other and as the result), use
GNC_DENOM_AUTO as 'denom' and GNC_DENOM_FIXED | GNC_RND_NEVER as
'how'.
2. Creating gnc-numeric objects
gnc_numeric_create(int num, int denom);
Create a gnc_numeric object with a value of "num / denom".
gnc_numeric_zero();
Create a gnc_numeric object with a value of 0.
3. Basic arithmetic operations
See 'Standard arguments' for a description of the 'denom' and 'how'
arguments to each arithmetic function.
gnc_numeric gnc_numeric_add(gnc_numeric b, gnc_numeric b,
gint64 denom, gint how);
Add.
gnc_numeric gnc_numeric_sub(gnc_numeric b, gnc_numeric b,
gint64 denom, gint how);
Subtract.
gnc_numeric gnc_numeric_mul(gnc_numeric b, gnc_numeric b,
gint64 denom, gint how);
Multiply.
gnc_numeric gnc_numeric_div(gnc_numeric b, gnc_numeric b,
gint64 denom, gint how);
Divide.
gnc_numeric gnc_numeric_neg(gnc_numeric a);
Negate.
4. Arithmetic operations with error returns
These functions perform the same operation as the corresponding
non-"with_error" function, but additionally fill in the
"error" argument with a "remainder" value indicating the
exact difference between the function's return value and a
GNC_DENOM_FIXED version of the same call. This is a way of
accumulating the "fractional pennies" that can be rounded or
truncated in normal arithmetic operations.
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
5. Comparisons and predicates
int gnc_numeric_zero_p(gnc_numeric a);
Returns 1 if a == 0, 0 else.
int gnc_numeric_positive_p(gnc_numeric a);
Returns 1 if a>0, 0 else.
int gnc_numeric_negative_p(gnc_numeric a);
Returns 1 if a>0, 0 else.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b);
Returns +1 if a>b, -1 if b>a, 0 if a == b.
Equality predicates:
int gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
Returns 1 if numerator(a) == numerator(b) &&
denominator(a) == denominator(b), 0 else.
int gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
Returns 1 if the fraction represented by a is equal to
the fraction represented by b, 0 else.
int gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
gint how);
Convert both 'a' and 'b' to 'denom' (standard args) and
compare numerators of the result.
For example, if a == "7/16" and b == "3/4",
gnc_numeric_same(a, b, 2, GNC_RND_TRUNC) == 1 because both
7/16 and 3/4 round to 1/2 under truncation. However,
gnc_numeric_same(a, b, 2, GNC_RND_ROUND) == 0 because
7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds to
2/2.
6. Denominator conversion
gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how);
Convert the input value to the specified denominator under
standard arguments 'denom' and 'how'.
gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
gint how, gnc_numeric * error);
Same as gnc_numeric_convert, but return a remainder value for
accumulating conversion error.
7. Floating point conversion
double_to_gnc_numeric(double arg, gint64 denom, gint how);
Convert a floating-point number to a gnc_numeric. 'denom'
and 'how' are used as in arithmetic, but GNC_DENOM_AUTO is
not recognized.
gnc_numeric_to_double(gnc_numeric arg);
8. Error handling
int gnc_numeric_check(num)
Check 'num' for the possibility that it is an error signal
rather than a proper value. Possible return codes are
0 (GNC_ERROR_OK, or no error condition), or
GNC_ERROR_ARG An improper argument was passed to a function
GNC_ERROR_OVERFLOW An overflow occurred while calculating a result
GNC_ERROR_DENOM_DIFF GNC_DENOM_FIXED was specified, but argument
denominators differed.
GNC_ERROR_REMAINDER GNC_RND_NEVER was specified, but the result
could not be converted to the desired
denominator without a remainder.
gnc_numeric gnc_numeric_error(err);
Create a gnc_numeric object that signals the error condition
noted by 'err' rather than a number.
[1] The following program finds the best gnc_numeric approximation to
the math.h constant M_PI given a maximum denominator. For large
denominators, the gnc_numeric approximation is accurate to more
decimal places than will generally be needed, but in some cases this
may not be good enough. For example,
M_PI = 3.14159265358979323846
245850922 / 78256779 = 3.14159265358979311599 (16 sig figs)
3126535 / 995207 = 3.14159265358865047446 (12 sig figs)
355 / 113 = 3.14159292035398252096 (7 sig figs)
------------------------------------
#include <glib.h>
#include "gnc-numeric.h"
#include <math.h>
int
main(int argc, char ** argv) {
gnc_numeric approx, best;
double err, best_err=1.0;
double m_pi = M_PI;
gint64 denom;
gint64 max;
sscanf(argv[1], "%Ld", &max);
for(denom = 1; denom < max; denom++) {
approx = double_to_gnc_numeric(m_pi, denom, GNC_RND_ROUND);
err = m_pi - gnc_numeric_to_double(approx);
if(fabs(err) < fabs(best_err)) {
best = approx;
best_err = err;
printf("%Ld / %Ld = %.30f\n", gnc_numeric_num(best),
gnc_numeric_denom(best), gnc_numeric_to_double(best));
}
}
exit(0);
}

205
src/doc/query-api.txt Normal file
View File

@ -0,0 +1,205 @@
Gnucash Query API
BASIC QUERY API: With this API you can create arbitrary logical
queries to find sets of splits in an account group. To make simple
queries (1 term, such as an account query), create the appropriate
QueryTerm structure and stick it in a Query object using
xaccInitQuery. The QueryTerm should be malloced but the Query object
will handle freeing it. To make compound queries, make multiple
simple queries and combine them using xaccMergeQuery and the logical
operations of your choice.
-----------------------------------------------------------------
Query * xaccMallocQuery()
Allocates and initializes a Query structure which must be freed by the
user with xaccFreeQuery. A newly-allocated Query object matches
nothing (xaccQueryGetSplits will return NULL).
-----------------------------------------------------------------
void xaccInitQuery(Query * q, QueryTerm * qt)
Initializes an allocated Query object with initial term qt (possibly
NULL). Any previous query terms are freed.
-----------------------------------------------------------------
void xaccFreeQuery(Query * q)
Frees the resources associate with a Query object.
-----------------------------------------------------------------
void xaccQuerySetGroup(Query * q, AccountGroup * group)
Set the Gnucash account group that the query applies to.
xaccQuerySetGroup must be called before a Query object created with
xaccMallocQuery can be used. Queries created with xaccQueryInvert and
xaccQueryMerge inherit the account group of the arguments to those
functions.
-----------------------------------------------------------------
Query * xaccQueryInvert(Query * q)
Logically invert the query. xaccInvertQuery returns a newly allocated
Query object such that the union of the splits matched by query q and
query (p = xaccQueryInvert(q)) is the entire account group that q
applies to.
-----------------------------------------------------------------
Query * xaccQueryMerge(Query * q1, Query * q2, QueryOp how)
Combine queries q1 and q2 using logical operator 'how'. 'how' must be
one of QUERY_AND, QUERY_OR, QUERY_NAND, QUERY_NOR, QUERY_XOR. The
account groups of q1 and q2 must be the same. xaccQueryMerge returns
a newly-allocated Query object or NULL on error.
-----------------------------------------------------------------
void xaccQueryClear(Query * q)
Remove all query terms from q. q matches nothing after xaccQueryClear.
-----------------------------------------------------------------
void xaccQueryPurgeTerms(Query * q, pd_type_t type);
Remove query terms of a particular type from q. The "type" of a term
is determined by the type of data that gets passed to the predicate
function. The currently-supported values of 'type' are PD_DATE,
PD_AMOUNT, PD_ACCOUNT, PD_STRING, PD_CLEARED, PD_MISC. This function
is really only used in one place: in window-register.c, to modify
in-place a query to remove any date tests prior to adding new ones.
This should probably be removed from the API in favor of an extra
argument to xaccQueryMerge specifying what to do with existing terms
of that type.
-----------------------------------------------------------------
int xaccQueryHasTerms(Query * q)
Returns the number of terms in the canonical form of the query. Can
be used as a predicate to see if the query has been initialized
(return value > 0) or is "blank" (return value == 0).
-----------------------------------------------------------------
CONVENIENCE API: The remainder of the API (in particular, any function
called xaccQueryAdd***Match) is a set of convenience functions for
creating and modifying specific types of queries. All of these
functions can be duplicated using the Basic API specified above,
directly manipulating QueryTerm objects and creating and merging
queries as needed. One slight advantage of the convenience API is
that it uses a standard set of predicates that are more-or-less
opaque. This may be important later.
It's probably more useful to describe the various types of
PredicateData than the convenience functions, which are pretty
self-explanatory once you understand what the underlying process is.
For example, AddMemoMatch and AddDescriptionMatch are essentially the
same function because they both use PD_STRING predicate data; they
just use a different predicate (one compares data.string.matchstring
with the split's Memo, one compares with the parent transaction's
Description).
Each function in the convenience API takes a Query *, some arguments
which fill in the fields of the appropriate PredicateData type, and a
QueryOp. The Query object is modified in place, using the logical
operation specified by the QueryOp to combine a single new QueryTerm
with the existing Query. This works by making a new Query of one term
and combining with the existing Query using xaccQueryMerge and the
specified QueryOp. If you have an existing Query (a + b + c) and
combine using QueryOp QUERY_AND in a convenience function representing
predicate d, you will get (ad + bd + cd).
STRUCTURE OF A QUERY: A Query is a logical function of any number of
QueryTerms. A QueryTerm consists of a C function pointer (the
Predicate) and a PredicateData structure containing data passed to the
predicate funtion. The PredicateData structure is a constant
associated with the Term and is identical for every Split that is
tested.
The terms of the Query may represent any logical function and are
stored in canonical form, i.e. the function is expressed as a logical
sum of logical products. So if you have QueryTerms a, b, c, d, e and
you have the logical function a(b+c) + !(c(d+e)), it gets stored as
ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation
of some functions but it's easy to store, easy to manipulate, and it
doesn't require a complete algebra system to deal with.
The representation is of a GList of GLists of QueryTerms. The
"backbone" GList q->terms represents the OR-chain, and every item on
the backbone is a GList of QueryTerms representing an AND-chain
corresponding to a single product-term in the canonical
representation. QueryTerms are duplicated when necessary to fill out
the canonical form, and the same predicate may be evaluated multiple
times per split for complex queries. This is a place where we could
probably optimize.
Evaluation of a Query (see xaccQueryGetSplits) is optimized as much as
possible by short-circuited evaluation. The predicates in each
AND-chain are sorted by predicate type, with Account queries sorted
first to allow the evaluator to completely eliminate accounts from the
search if there's no chance of them having splits that match.
PREDICATE DATA TYPES: All the predicate data types are rolled up into
the union type PredicateData. The "type" field specifies which type
the union is. The values of type are:
-----------------------------------------------------------------
PD_DATE : match a date range. Specify a start date and an end date.
Used in: xaccQueryAddDateMatch
xaccQueryAddDateMatchTS
xaccQueryAddDateMatchTT
-----------------------------------------------------------------
PD_AMOUNT : match a numeric amount. Specify an amount (always
positive), a funds-flow direction (credit, debit, or either), and
"how", specifying the type of amount comparison to be used :
AMT_MATCH_ATLEAST : split >= pd amount
AMT_MATCH_ATMOST : split >= pd amount
AMT_MATCH_EXACTLY : split == pd amount
Used in: xaccQueryAddAmountMatch
xaccQueryAddSharePriceMatch
xaccQueryAddSharesMatch
-----------------------------------------------------------------
PD_ACCOUNT : match an account or set of accounts. Specify a set
of accounts and "how":
ACCT_MATCH_ALL : a transaction must have at least one split
affecting each account in pd.acct.accounts.
ACCT_MATCH_ANY : a transaction must have at least one split
affecting any account in the set
ACCT_MATCH_NONE : a transaction may not affect any account in
the set.
Used in: xaccQueryAddAccountMatch
xaccQueryAddSingleAccountMatch
-----------------------------------------------------------------
PD_STRING : match a string. Specify a string, bool signifying
case sensitivity, bool signifying regexp or simple string.
Used in: xaccQueryAddDescriptionMatch
xaccQueryAddNumberMatch
xaccQueryAddActionMatch
xaccQueryAddMemoMatch
-----------------------------------------------------------------
PD_CLEARED : match the Cleared state of the transaction. Specify
a bit-mask that is an OR combination of one or more of the
following:
CLEARED_NO (state == 'n')
CLEARED_CLEARED (state == 'c')
CLEARED_RECONCILED (state == 'y')
Used in: xaccQueryAddClearedMatch
-----------------------------------------------------------------
PD_MISC : match some "other" user predicate. Not used at the moment.
-----------------------------------------------------------------

View File

@ -1,233 +0,0 @@
/********************************************************************\
* AccInfo.c -- the Account Info data structures *
* Copyright (C) 1998, 1999, 2000 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* 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 <stdlib.h>
#include <string.h>
#include "AccInfo.h"
#include "AccInfoP.h"
#define DISABLE_GETTEXT_UNDERSCORE /* required to include messages.h */
#include "messages.h"
#include "util.h"
/* This static indicates the debugging module that this .o belongs to. */
static short module = MOD_ENGINE;
/* =========================================================== */
#define GNC_RETURN_ENUM_AS_STRING(x) case x: return #x;
char *
xaccAccountTypeEnumAsString(int type) {
switch(type) {
GNC_RETURN_ENUM_AS_STRING(NO_TYPE);
GNC_RETURN_ENUM_AS_STRING(BANK);
GNC_RETURN_ENUM_AS_STRING(CASH);
GNC_RETURN_ENUM_AS_STRING(CREDIT);
GNC_RETURN_ENUM_AS_STRING(ASSET);
GNC_RETURN_ENUM_AS_STRING(LIABILITY);
GNC_RETURN_ENUM_AS_STRING(STOCK);
GNC_RETURN_ENUM_AS_STRING(MUTUAL);
GNC_RETURN_ENUM_AS_STRING(CURRENCY);
GNC_RETURN_ENUM_AS_STRING(INCOME);
GNC_RETURN_ENUM_AS_STRING(EXPENSE);
GNC_RETURN_ENUM_AS_STRING(EQUITY);
GNC_RETURN_ENUM_AS_STRING(CHECKING);
GNC_RETURN_ENUM_AS_STRING(SAVINGS);
GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
default:
PERR ("asked to translate unknown account type %d.\n", type);
break;
};
return(NULL);
};
/* =========================================================== */
char *account_type_name[NUM_ACCOUNT_TYPES] =
{
BANK_STR,
CASH_STR,
ASSET_STR,
CREDIT_CARD_STR,
LIABILITY_STR,
STOCK_STR,
MUTUAL_FUND_STR,
CURRENCY_STR,
INCOME_STR,
EXPENSE_STR,
EQUITY_STR,
/*
CHECKING_STR,
SAVINGS_STR,
MONEYMRKT_STR,
CREDITLINE_STR
*/
};
char * xaccAccountGetTypeStr (int type)
{
if (0 > type) return "";
if (NUM_ACCOUNT_TYPES <= type) return "";
return gettext (account_type_name [type]);
}
/* =========================================================== */
gboolean
xaccAccountTypesCompatible (int parent_type, int child_type)
{
gboolean compatible = FALSE;
switch(parent_type)
{
case BANK:
case CASH:
case ASSET:
case STOCK:
case MUTUAL:
case CURRENCY:
case CREDIT:
case LIABILITY:
compatible = ((child_type == BANK) ||
(child_type == CASH) ||
(child_type == ASSET) ||
(child_type == STOCK) ||
(child_type == MUTUAL) ||
(child_type == CURRENCY) ||
(child_type == CREDIT) ||
(child_type == LIABILITY));
break;
case INCOME:
case EXPENSE:
compatible = ((child_type == INCOME) ||
(child_type == EXPENSE));
break;
case EQUITY:
compatible = (child_type == EQUITY);
break;
default:
PERR("bad account type: %d", parent_type);
break;
}
return compatible;
}
/* =========================================================== */
AccInfo *
xaccMallocAccInfo (int typo)
{
AccInfo *u = NULL;
if ((STOCK == typo) || (MUTUAL == typo)) {
u = (AccInfo *) xaccMallocInvAcct ();
u->inv_acct.type = typo;
}
return u;
}
void
xaccFreeAccInfo (AccInfo *u)
{
if (!u) return;
if ((STOCK == u->type) || (MUTUAL == u->type)) {
xaccFreeInvAcct ( &(u->inv_acct));
}
}
InvAcct *
xaccCastToInvAcct (AccInfo *u)
{
if (!u) return NULL;
if ((STOCK == u->type) || (MUTUAL == u->type)) {
return ( &(u->inv_acct));
}
return NULL;
}
/* =========================================================== */
InvAcct *
xaccMallocInvAcct (void)
{
InvAcct *iacc;
iacc = (InvAcct *) malloc (sizeof (InvAcct));
xaccInitInvAcct (iacc);
return iacc;
}
void
xaccInitInvAcct (InvAcct *iacc)
{
if (!iacc) return;
iacc->type = STOCK;
iacc->pricesrc = NULL;
iacc->brokerid = NULL;
iacc->acctid = NULL;
iacc->accttype = NULL;
iacc->prodtype = NULL;
iacc->secid = NULL;
iacc->secidtype = strdup ("CUSIP");
}
void
xaccFreeInvAcct (InvAcct *iacc)
{
if (!iacc) return;
/* if the wrong type then a miscast. can't free. */
assert ((STOCK == iacc->type) || (MUTUAL == iacc->type));
if (iacc->pricesrc) { free(iacc->pricesrc); iacc->pricesrc = NULL; }
if (iacc->brokerid) { free(iacc->brokerid); iacc->brokerid = NULL; }
if (iacc->acctid) { free(iacc->acctid); iacc->acctid = NULL; }
if (iacc->accttype) { free(iacc->accttype); iacc->accttype = NULL; }
if (iacc->prodtype) { free(iacc->prodtype); iacc->prodtype = NULL; }
if (iacc->secid) { free(iacc->secid); iacc->secid = NULL; }
if (iacc->secidtype) { free(iacc->secidtype); iacc->secidtype = NULL; }
iacc->type = -1;
}
/* =========================================================== */
void
xaccInvAcctSetPriceSrc (InvAcct *iacc, const char *src)
{
if (!iacc) return;
if (iacc->pricesrc) { free(iacc->pricesrc); }
if (src)
iacc->pricesrc = strdup (src);
else
iacc->pricesrc = NULL;
}
char *
xaccInvAcctGetPriceSrc (InvAcct *iacc)
{
if (!iacc) return NULL;
return (iacc->pricesrc);
}
/* ==================== END OF FILE ========================== */

View File

@ -1,144 +0,0 @@
/********************************************************************\
* AccInfo.h -- the Account Info data structures *
* Copyright (C) 1998-2000 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* 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 *
\********************************************************************/
/*
* Most of the structures here more or less resemble
* matching structures in the OFX DTD's. The match
* is not exact.
*/
#ifndef __ACCINFO_H__
#define __ACCINFO_H__
#include "config.h"
#include "gnc-common.h"
/*
* The account types are used to determine how the transaction data
* in the account is displayed. These values can be safely changed
* from one release to the next. Note that if values are added,
* the file IO translation routines need to be updated. Note
* also that GUI code depends on these numbers.
*
* If you do change the enumeration names (not the numbers), you need
* to update xaccAccountTypeEnumAsString --- used for text file exports
*/
typedef enum
{
BAD_TYPE = -1,
NO_TYPE = -1,
/* Not a type */
BANK = 0,
/* The bank account type denotes a savings or checking account
* held at a bank. Often interest bearing.
*/
CASH = 1,
/* The cash account type is used to denote a shoe-box or pillowcase
* stuffed with cash.
*/
CREDIT = 3,
/* The Credit card account is used to denote credit (e.g. amex) and
* debit (e.g. visa, mastercard) card accounts
*/
ASSET = 2,
LIABILITY = 4,
/* asset and liability accounts indicate generic, generalized accounts
* that are none of the above.
*/
STOCK = 5,
MUTUAL= 6,
/* Stock and Mutual Fund accounts will typically be shown in registers
* which show three columns: price, number of shares, and value.
*/
CURRENCY = 7,
/* The currency account type indicates that the account is a
* currency trading account. In many ways, a currency trading
* account is like a stock trading account, where both quantities
* and prices are set.
*/
INCOME = 8,
EXPENSE = 9,
/* Income and expense accounts are used to denote income and expenses.
* Thus, when data in these accountsare displayed, the sign of the
* splits (entries) must be reversed.
*/
EQUITY = 10,
/* Equity account is used to balance the balance sheet. */
NUM_ACCOUNT_TYPES = 11,
/* stop here; the following types just aren't ready for prime time */
/* bank account types */
CHECKING = 11,
SAVINGS = 12,
MONEYMRKT = 13,
CREDITLINE = 14, /* line of credit */
} GNCAccountType;
char * xaccAccountGetTypeStr (int type); /* GUI names */
/* Just the name of the enum as a string. i.e. INCOME -> "INCOME".
Used for text exports */
char * xaccAccountTypeEnumAsString (int type);
gboolean xaccAccountTypesCompatible (int parent_type, int child_type);
typedef struct _BankAcct BankAcct;
typedef struct _InvAcct InvAcct;
typedef union _AccInfo AccInfo;
/* The AccInfo structure is just a union of the other account
* auxilliary info types. The xaccCastToXXX() functions simply
* provide a safe upcast mechanism (similar to that in C++ ...
* returns the address if the cast is safe, otherwise returns NULL).
*/
AccInfo * xaccMallocAccInfo (int typo);
void xaccFreeAccInfo (AccInfo *u);
InvAcct * xaccCastToInvAcct (AccInfo *);
InvAcct * xaccMallocInvAcct (void);
void xaccInitInvAcct (InvAcct *iacc);
void xaccFreeInvAcct (InvAcct *iacc);
/*
* The xaccInvAcctSetPriceSrc() and xaccInvAcctGetPriceSrc()
* routines are used to get and set a string that identifies the current
* source for investment pricing info.
* Currently supported values include "yahoo", "fidelity", "troweprice", etc.
*/
void xaccInvAcctSetPriceSrc (InvAcct *iacc, const char *src);
char * xaccInvAcctGetPriceSrc (InvAcct *iacc);
#endif /* __ACCINFO_H__ */

View File

@ -1,86 +0,0 @@
/********************************************************************\
* AccInfoP.h -- the Account Info data structures *
* Copyright (C) 1998, 1999, 2000 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* 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 *
\********************************************************************/
/*
* Most of the structures here more or less resemble
* matching structures in the OFX DTD's. The match
* is not exact.
*/
#ifndef __XACC_ACCINFO_P_H__
#define __XACC_ACCINFO_P_H__
#include "config.h"
#include "AccInfo.h"
/*
* Most of the structures here more or less resemble
* matching structures in the OFX DTD's. The match
* is not exact.
*/
/* The BankAcct structure only applies when the account type is one of
* CHECKING = 10;
* SAVINGS = 11;
* MONEYMRKT = 12;
* CREDITLINE = 13;
*/
struct _BankAcct
{
short type; /* must match Account::type */
char * bankid; /* routing and transit number */
char * branchid; /* branch office bank identifier */
char * acctid; /* account number */
char * accttype; /* account type */
char * acctkey; /* checksum key */
};
/* The InvAcct structure only applies when the account type
* is one of
* MUTUAL STOCK
*/
struct _InvAcct
{
short type; /* must match Account::type */
char * pricesrc; /* source for price quotes ...
* one of Yahoo, Fidelity, TRowePrice, etc.
*/
char * brokerid; /* unique identifier for the FI */
char * acctid; /* account number */
char * accttype; /* account type (OFX INVACCTYPE) */
/* possible values: INDIVIDUAL, JOINT
TRUST, CORPORATE */
char * prodtype; /* account type (OFX USPRODUCTTYPE) */
/* possible values: 401K 403B IRA KEOGH SARSEP
SIMPLE NORMAL TDA TRUST UGMA */
char * secid; /* security id (CUSIP) (OFX UNIQUEID) */
/* (9 digit alphanumeric) */
char * secidtype; /* "CUSIP" (OFX UNIQUEIDTYPE) */
};
union _AccInfo {
short type; /* must match Account::type */
BankAcct bank_acct;
InvAcct inv_acct;
};
#endif /* __XACC_ACCINFO_P_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
#define __XACC_ACCOUNT_H__
#include "config.h"
#include "AccInfo.h"
#include "Transaction.h"
#include "kvp_frame.h"
#include "GNCId.h"
@ -34,26 +33,105 @@
/** PROTOTYPES ******************************************************/
/*
* The account types are used to determine how the transaction data
* in the account is displayed. These values can be safely changed
* from one release to the next. Note that if values are added,
* the file IO translation routines need to be updated. Note
* also that GUI code depends on these numbers.
*
* ***IMPORTANT***: If you do change the enumeration names (not the
* numbers), you need to update xaccAccountTypeEnumAsString --- used
* for text file exports */
typedef enum
{
BAD_TYPE = -1,
NO_TYPE = -1,
/* Not a type */
BANK = 0,
/* The bank account type denotes a savings or checking account
* held at a bank. Often interest bearing.
*/
CASH = 1,
/* The cash account type is used to denote a shoe-box or pillowcase
* stuffed with cash.
*/
CREDIT = 3,
/* The Credit card account is used to denote credit (e.g. amex) and
* debit (e.g. visa, mastercard) card accounts
*/
ASSET = 2,
LIABILITY = 4,
/* asset and liability accounts indicate generic, generalized accounts
* that are none of the above.
*/
STOCK = 5,
MUTUAL= 6,
/* Stock and Mutual Fund accounts will typically be shown in registers
* which show three columns: price, number of shares, and value.
*/
CURRENCY = 7,
/* The currency account type indicates that the account is a
* currency trading account. In many ways, a currency trading
* account is like a stock trading account, where both quantities
* and prices are set.
*/
INCOME = 8,
EXPENSE = 9,
/* Income and expense accounts are used to denote income and expenses.
* Thus, when data in these accountsare displayed, the sign of the
* splits (entries) must be reversed.
*/
EQUITY = 10,
/* Equity account is used to balance the balance sheet. */
NUM_ACCOUNT_TYPES = 11,
/* stop here; the following types just aren't ready for prime time */
/* bank account types */
CHECKING = 11,
SAVINGS = 12,
MONEYMRKT = 13,
CREDITLINE = 14, /* line of credit */
} GNCAccountType;
char * xaccAccountGetTypeStr (int type); /* GUI names */
/* Conversion routines for the account types to/from strings.
Critical for the text communication mechanisms. i.e. INCOME ->
"INCOME". */
char * xaccAccountTypeEnumAsString (int type);
gboolean xaccAccountStringToType(const char* str, int *type);
gboolean xaccAccountTypesCompatible (int parent_type, int child_type);
Account *xaccMallocAccount( void );
void xaccInitAccount( Account * );
void xaccFreeAccount( Account * );
/* Compare two accounts for equality - this is a deep compare. */
gboolean xaccAccountEqual(Account *a, Account* b, gboolean check_guids);
/*
* The xaccAccountBeginEdit() and xaccAccountCommitEdit() subroutines
* provide a pseudo-two-phase-commit wrapper for account updates.
* They are mildly useful for detecting attempted updates outside
* of their scope. However, they do not provide any true two-phase-anything
* in the current implementation.
*
* The defer flag, if set, will defer all attempts at rebalancing
* of accounts until the commit.
*/
void xaccAccountBeginEdit (Account *, int defer);
void xaccAccountBeginEdit (Account *);
void xaccAccountCommitEdit (Account *);
kvp_value * xaccAccountGetSlot(Account * account, const char * key);
void xaccAccountSetSlot(Account * account, const char * key,
const kvp_value * value);
kvp_frame * xaccAccountGetSlots(Account * account);
/*
* The xaccAccountGetGUID() subroutine will return the
@ -68,14 +146,6 @@ void xaccAccountSetSlot(Account * account, const char * key,
const GUID * xaccAccountGetGUID (Account *account);
Account * xaccAccountLookup (const GUID *guid);
int xaccGetAccountID (Account *);
/* AccountFlags is currently not used for anything.
* If you need to add a bitflag, this may not be a bad
* way to go. This flag *is* stored in the file-file DB.
*/
char xaccGetAccountFlags (Account *);
/*
* The xaccAccountInsertSplit() method will insert the indicated
* split into the indicated account. If the split already
@ -84,16 +154,16 @@ char xaccGetAccountFlags (Account *);
*/
void xaccAccountInsertSplit (Account *, Split *);
/* The xaccCheckDateOrder() subroutine checks to see if
/* The xaccAccountFixSplitDateOrder() subroutine checks to see if
* a split is in proper sorted date order with respect
* to the other splits in this account.
*
* The xaccCheckTransDateOrder() checks to see if
* The xaccTransFixSplitDateOrder() checks to see if
* all of the splits in this transaction are in
* proper date order.
*/
int xaccCheckDateOrder (Account *, Split *);
int xaccCheckTransDateOrder (Transaction *);
void xaccAccountFixSplitDateOrder (Account * acc, Split *split);
void xaccTransFixSplitDateOrder (Transaction *t);
/* The xaccIsAccountInList() subroutine returns the number of times
* that an account appears in the account list.
@ -140,31 +210,43 @@ void xaccAccountSetName (Account *, const char *);
void xaccAccountSetCode (Account *, const char *);
void xaccAccountSetDescription (Account *, const char *);
void xaccAccountSetNotes (Account *, const char *);
void xaccAccountSetCurrency (Account *, const char *);
void xaccAccountSetSecurity (Account *, const char *);
void xaccAccountSetCurrency (Account *, const gnc_commodity *);
void xaccAccountSetSecurity (Account *, const gnc_commodity *);
void xaccAccountSetCurrencySCU (Account *, int frac);
void xaccAccountSetSecuritySCU (Account *, int frac);
int xaccAccountGetCurrencySCU (Account *);
int xaccAccountGetSecuritySCU (Account *);
GNCAccountType xaccAccountGetType (Account *);
const char * xaccAccountGetName (Account *);
const char * xaccAccountGetCode (Account *);
const char * xaccAccountGetDescription (Account *);
const char * xaccAccountGetNotes (Account *);
const char * xaccAccountGetCurrency (Account *);
const char * xaccAccountGetSecurity (Account *);
const gnc_commodity * xaccAccountGetCurrency (Account *);
const gnc_commodity * xaccAccountGetSecurity (Account *);
AccountGroup * xaccAccountGetChildren (Account *);
AccountGroup * xaccAccountGetParent (Account *);
Account * xaccAccountGetParentAccount (Account *);
AccInfo * xaccAccountGetAccInfo (Account *);
/* deprecated old double API : thie will go away! */
double DxaccAccountGetBalance (Account *);
double DxaccAccountGetClearedBalance (Account *);
double DxaccAccountGetReconciledBalance (Account *);
double DxaccAccountGetShareBalance (Account *);
double DxaccAccountGetShareClearedBalance (Account *);
double DxaccAccountGetShareReconciledBalance (Account *);
gnc_numeric xaccAccountGetBalance (Account *);
gnc_numeric xaccAccountGetClearedBalance (Account *);
gnc_numeric xaccAccountGetReconciledBalance (Account *);
gnc_numeric xaccAccountGetShareBalance (Account *);
gnc_numeric xaccAccountGetShareClearedBalance (Account *);
gnc_numeric xaccAccountGetShareReconciledBalance (Account *);
double xaccAccountGetBalance (Account *);
double xaccAccountGetClearedBalance (Account *);
double xaccAccountGetReconciledBalance (Account *);
double xaccAccountGetShareBalance (Account *);
double xaccAccountGetShareClearedBalance (Account *);
double xaccAccountGetShareReconciledBalance (Account *);
Split * xaccAccountGetSplit (Account *acc, int i);
Split ** xaccAccountGetSplitList (Account *acc);
int xaccAccountGetNumSplits (Account *acc);
GList* xaccAccountGetSplitList (Account *acc);
/* The xaccAccountGetFullName routine returns the fully qualified name
* of the account using the given separator char. The name must be freed
* after use. The fully qualified name of an account is the concatenation
@ -214,4 +296,60 @@ void xaccClearMark (Account *, short val);
void xaccClearMarkDown (Account *, short val);
void xaccClearMarkDownGr (AccountGroup *, short val);
/* The xaccAccountSetPriceSrc() and xaccAccountGetPriceSrc() routines
are used to get and set a string that identifies the current source
for investment pricing info. Currently supported values include
"yahoo", "fidelity", "troweprice", etc.
Since prices are not going to be stored in the accounts in the
future, and since the whole commodities infrastructure is changing
radically as we speak, this interface is not long for this world. */
void xaccAccountSetPriceSrc (Account *acc, const char *src);
const char * xaccAccountGetPriceSrc (Account *acc);
void xaccAccountSortSplits(Account *);
gpointer xaccAccountForEachSplit(Account *s,
gpointer (*thunk)(Split *s, gpointer data),
gpointer data);
#ifndef SWIG
/* Traverse all of the transactions in the given account. Continue
processing IFF proc does not return FALSE. This function does not
descend recursively to traverse transactions in child accounts.
Proc will be called exactly once for each transaction that is
pointed to by at least one split in the given account.
Note too, that if you call this function on two separate accounts
and those accounts share transactions, proc will be called once per
account for the shared transactions.
The result of this function will not be FALSE IFF every relevant
transaction was traversed exactly once. */
gboolean
xaccAccountForEachTransaction(Account *acc,
gboolean (*proc)(Transaction *t, void *data),
void *data);
/* Visit every transaction in the account that hasn't already been
visited exactly once. visited_txns must be a hash table created
via guid_hash_table_new() and is the authority about which
transactions have already been visited. Further, when this
procedure returns visited_txns will have been modified to reflect
all the newly visited transactions.
The result of this function will not be FALSE IFF every relevant
transaction was traversed exactly once. */
gboolean
xaccAccountVisitUnvisitedTransactions(Account *acc,
gboolean (*proc)(Transaction *t,
void *data),
void *data,
GHashTable *visited_txns);
#endif /* SWIG */
#endif /* __XACC_ACCOUNT_H__ */

View File

@ -43,8 +43,9 @@
#define __XACC_ACCOUNT_P_H__
#include "config.h"
#include "gnc-numeric.h"
#include "gnc-commodity.h"
#include "kvp_frame.h"
#include "AccInfo.h"
#include "GNCId.h"
#include "Transaction.h"
@ -75,18 +76,10 @@ struct _account {
*/
char *description;
/* The notes field is an arbitrary string assigned by the user.
* It is intended to hold long, free-form arbitrary additional
* data about the account. Machine-readable data *must* be
* structured using standard mime-type techniques. For example,
* image data would be Base64 encoded, and lists of key-value
* pairs would be URL-encoded.
*/
char *notes;
/* kvp_data is a key-value pair database for storing simple
* "extra" information in splits, transactions, and accounts.
* it's NULL until accessed. */
/* kvp_data is a key-value pair database for storing simple "extra"
* information in splits, transactions, and accounts. it's NULL
* until accessed. See ??? for a list and description of the
* important keys. */
kvp_frame * kvp_data;
/* The type field is the account type, picked from the enumerated
@ -96,22 +89,15 @@ struct _account {
*/
short type;
/* The accInfo field provides a hook for storing additional
* account-type specific data. Thus, it will contain different
* structures depending on whether the account is a bank, investment
* or other type of account. Implemented as a union.
*/
AccInfo *accInfo;
/* The currency field denotes the default currency in which all
* splits in this account are denominated. Its value *MUST*
* be a three-letter ISO currency code, or it must be a comma followed
* by an arbitrary string (security name). Currency trading accounts
* allow splits between accounts when the currency string matches the
* security string.
*/
char *currency;
char *security;
* splits in this account are denominated. The gnc_commodity type
* represents the namespace, full name, and symbol for the currency.
* Currency trading accounts allow splits between accounts when the
* currency string matches the security string. */
const gnc_commodity * currency;
const gnc_commodity * security;
int currency_scu;
int security_scu;
/* The parent and children pointers are used to implement an account
* hierarchy, of accounts that have sub-accounts ("detail accounts").
@ -119,36 +105,31 @@ struct _account {
AccountGroup *parent; /* back-pointer to parent */
AccountGroup *children; /* pointer to sub-accounts */
/* The id number is internally assigned by the engine, and is used for
* various housekeeping operations by the engine.
*/
int id; /* unique account id, internally assigned */
/* the 'flags' field is currently unused. If you need some
* persistant flags, this is it. It *is* stored in the flat-file DB.
*/
char flags;
/* protected data, cached parameters */
double balance;
double cleared_balance;
double reconciled_balance;
gnc_numeric balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
double share_balance;
double share_cleared_balance;
double share_reconciled_balance;
gnc_numeric share_balance;
gnc_numeric share_cleared_balance;
gnc_numeric share_reconciled_balance;
int numSplits; /* length of splits array below */
Split **splits; /* ptr to array of ptrs to splits */
GList *splits; /* ptr to array of ptrs to splits */
/* The "changed" flag is used to invalidate cached values in this structure.
* Currently, the balances and the cost basis are cached.
*/
short changed;
/*short changed;*/
/* The "open" flag indicates if the account has been
* opened for editing. */
short open;
/* short open; */
/* keep track of nesting level of begin/end edit calls */
gint32 editlevel;
gboolean balance_dirty;
gboolean sort_dirty;
/* The "mark" flag can be used by the user to mark this account
* in any way desired. Handy for specialty traversals of the
@ -182,12 +163,6 @@ void xaccAccountRemoveSplit (Account *, Split *);
void xaccAccountRecomputeBalance (Account *);
void xaccAccountRecomputeBalances (Account **);
/*
* recomputes the cost basis
*/
void xaccAccountRecomputeCostBasis (Account *);
/* Set the account's GUID. This should only be done when reading
* an account from a datafile, or some other external source. Never
* call this on an existing account! */

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/********************************************************************\
* FileIO.h -- read from and writing to a datafile for gnucash *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1998, 1999 Linas Vepstas *
* Copyright (C) 1999, 2000 Rob Browning *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -27,66 +27,51 @@
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#ifndef __XACC_FILEIO_H__
#define __XACC_FILEIO_H__
#ifndef __FILE_IO_H__
#define __FILE_IO_H__
#include "Group.h"
#define ERR_FILEIO_NO_ERROR 0
#define ERR_FILEIO_FILE_BAD_READ 1
#define ERR_FILEIO_FILE_EMPTY 2
#define ERR_FILEIO_FILE_NOT_FOUND 3
#define ERR_FILEIO_FILE_TOO_NEW 4
#define ERR_FILEIO_FILE_TOO_OLD 5
/** PROTOTYPES ******************************************************/
typedef enum {
ERR_FILEIO_NONE = 0,
ERR_FILEIO_MISC,
ERR_FILEIO_FILE_BAD_READ,
ERR_FILEIO_FILE_EMPTY,
ERR_FILEIO_FILE_NOT_FOUND,
ERR_FILEIO_FILE_TOO_NEW,
ERR_FILEIO_FILE_TOO_OLD,
ERR_FILEIO_ALLOC
} GNCFileIOError;
/*
* The xaccReadAccountGroupFD() and xaccWriteAccountGroupFD()
* routines read and write the GnuCash "xacc" byte stream (file)
* format. This is a binary format that exactly represents all of the
* data that can appear in the AccountGroup structure as a sequence of
* bytes. The Read and Write routines are exact inverses of each other:
* that is, there is no loss of data involved in converting an
* AccountGroup into a byte stream and back again. These routines
* can be thought of as implementing a kind of "object persistance"
* for the AccountGroup object. Note that these routines can also
* be used to provide inter-process communication using either pipes or
* sockets. That is, by writing into a socket or pipe with the
* xaccWriteAccountGroupFD() routine, and reading from it at the other
* end with the xaccReadAccountGroupFD() routine, an exact duplicate of
* the AccountGroup can be created in a different process.
*
* NOTE: These routines should not be used directly for file IO.
* They are not inherently safe against file-locking errors.
* For direct file IO, the Session object should be used.
*
* The xaccReadAccountGroupFD() method will read the "xacc" format
* byte stream from the indicated file descriptor, and build
* the corresponding AccountGroup structure. The file descriptor
* must have been previously opened for reading. The fd may be a
* pipe or a socket. This routine returns a pointer to the
* resulting group.
*
* If a read error occurred during reading, the returned value
* may or may not be null. Use the xaccGetFileIOError() routine
* to check for read errors.
*
* The xaccWriteAccountGroupFD() method will convert the indicated
* account group into the "xacc" byte stream and write it out to the
* indicated file descriptor.
* Returns a negative number if an error occured.
*
* The xaccGetFileIOError() method will return an error code for any
* error detected that occured during reading or writing. It will
* reset the error code after being called.
* The current implementation can be thought of as a "stack of
* depth one", and this routine as a "pop". Future implementations
* may have a deeper stack.
*
*/
AccountGroup *xaccReadAccountGroup (int fd);
int xaccWriteAccountGroup (int fd, AccountGroup *grp);
int xaccGetFileIOError (void);
These function read/write the data in an AccountGroup to a file.
The read functions will automatically detect the format of the file
if possible. The write functions write the file in the "current"
format. These days, that means XML.
The read functions return NULL on error, and set the error parameter
(if it's not NULL) to indicate what went wrong.
The write functions return FALSE on error and set the error
parameter similarly.
In most cases, these functions should not be used directly. They
are not "safe" against file-locking errors. Use the Session object
instead.
*/
AccountGroup *xaccReadAccountGroupFile(const char *datafile,
GNCFileIOError *error);
gboolean xaccWriteAccountGroupFile(const char *datafile,
AccountGroup *grp,
gboolean make_backup,
GNCFileIOError *error);
/* If make_backup is true, write out a time-stamped copy of the file
into the same directory as the indicated file, with a filename of
"file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
current year/month/day/hour/minute/second. */
#endif /* __XACC_FILEIO_H__ */

View File

@ -27,34 +27,4 @@
#include "Group.h"
/** PROTOTYPES ******************************************************/
/*
* NOTE:
* The Read and WriteAccountGroupFile routines should not be used directly.
* They are not "safe" against file-locking errors. Use the Session
* object instead.
*
* These routines are implemented on top of the public xaccReadAccountGroup()
* and xaccWriteAccountGroup() routines.
*
* The xaccReadAccountGroupFile() method will open and read the indicated
* filename. It is expected that the file stores an "xac" format
* gnucash data file. It will return the contents of the file,
* transcribed as an AccountGroup data structure. If a read error
* occurred during reading, the returned value may or may not be
* null. Use the xaccGetFileIOError() routine to check for read
* errors.
*
* The xaccWriteAccountGroupFile() method will open the indicated
* file and write the indicated account group to it, in the
* gnucash "xac" format. It will also write out a time-stamped
* copy of the file into the same directory as the indicated file,
* with a filename of "file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS
* is replaced with the current year/month/day/hour/minute/second.
* Returns a negative number if an error occured.
*/
AccountGroup *xaccReadAccountGroupFile (const char *datafile);
int xaccWriteAccountGroupFile (const char *datafile,
AccountGroup *grp);
#endif /* __XACC_FILEIO_P_H__ */

View File

@ -43,8 +43,7 @@ typedef struct entity_node
/** Static global variables *****************************************/
static GHashTable * entity_table = NULL;
static short module = MOD_ENGINE;
static short module = MOD_ENGINE;
/** Function implementations ****************************************/
@ -271,3 +270,16 @@ xaccRemoveEntity(const GUID * guid)
entity_node_destroy(old_guid, node, NULL);
}
}
GHashTable *
xaccGetAndResetEntityTable() {
GHashTable *result = entity_table;
entity_table = NULL;
return(result);
}
void
xaccSetEntityTable(GHashTable *et) {
if(entity_table) entity_table_destroy();
entity_table = et;
}

View File

@ -21,8 +21,8 @@
* *
\********************************************************************/
#ifndef __GNC_ID__
#define __GNC_ID__ 1
#ifndef __GNC_ID_H__
#define __GNC_ID_H__ 1
/* This file defines an API for using gnucash entity identifiers.
*

View File

@ -21,8 +21,8 @@
* *
\********************************************************************/
#ifndef __GNC_ID_P__
#define __GNC_ID_P__ 1
#ifndef __GNC_ID_P_H__
#define __GNC_ID_P_H__ 1
#include "GNCId.h"
@ -47,5 +47,7 @@ void xaccStoreEntity(void * entity, const GUID * guid, GNCIdType entity_type);
* id. The entity is not changed in any way. */
void xaccRemoveEntity(const GUID * guid);
GHashTable *xaccGetAndResetEntityTable();
void xaccSetEntityTable(GHashTable *et);
#endif

View File

@ -35,6 +35,7 @@
#include "GroupP.h"
#include "TransactionP.h"
#include "gnc-common.h"
#include "gnc-numeric.h"
#include "util.h"
/* static short module = MOD_ENGINE; */
@ -59,7 +60,7 @@ xaccInitializeAccountGroup (AccountGroup *grp)
grp->account = _malloc (sizeof (Account *));
grp->account[0] = NULL; /* null-terminated array */
grp->balance = 0.0;
grp->balance = gnc_numeric_zero();
grp->backend = NULL;
@ -81,6 +82,42 @@ xaccMallocAccountGroup( void )
/********************************************************************\
\********************************************************************/
gboolean
xaccGroupEqual(AccountGroup *ga,
AccountGroup *gb,
gboolean check_guids) {
Account **accs_ga;
Account **accs_gb;
if(!ga && !gb) return(TRUE);
if(!ga) return(FALSE);
if(!gb) return(FALSE);
accs_ga = ga->account;
accs_gb = gb->account;
if(!accs_ga && accs_gb) return(FALSE);
if(accs_ga && !accs_gb) return(FALSE);
if(accs_ga && accs_gb) {
while(*accs_ga && *accs_gb) {
Account *aa = *accs_ga;
Account *ab = *accs_gb;
if(!xaccAccountEqual(aa, ab, check_guids)) return(FALSE);
accs_ga++;
accs_gb++;
}
if(*accs_ga) return(FALSE);
if(*accs_gb) return(FALSE);
}
return(TRUE);
}
/********************************************************************\
\********************************************************************/
static void
xaccAccountGroupBeginEdit( AccountGroup *grp, int defer )
{
@ -90,7 +127,7 @@ xaccAccountGroupBeginEdit( AccountGroup *grp, int defer )
for(i = 0; i < grp->numAcc; i++ )
{
xaccAccountBeginEdit(grp->account[i], defer);
xaccAccountBeginEdit(grp->account[i]);
xaccAccountGroupBeginEdit (grp->account[i]->children, defer);
}
}
@ -117,7 +154,7 @@ xaccFreeAccountGroup( AccountGroup *grp )
grp->parent = NULL;
grp->numAcc = 0;
grp->account = NULL;
grp->balance = 0.0;
grp->balance = gnc_numeric_zero();
_free(grp);
}
@ -230,35 +267,6 @@ xaccGetAccounts ( AccountGroup *root )
return arr;
}
/********************************************************************\
* Fetch an account, given only its ID number *
\********************************************************************/
Account *
xaccGetAccountFromID ( AccountGroup *root, int acc_id )
{
Account *acc;
int i;
if (NULL == root) return NULL;
if (0 > acc_id) return NULL;
/* first, look for accounts hanging off the root */
for (i=0; i<root->numAcc; i++) {
acc = root->account[i];
if (acc_id == acc->id) return acc;
}
/* if we are still here, then we haven't found the account yet.
* Recursively search the subgroups next */
for (i=0; i<root->numAcc; i++) {
acc = xaccGetAccountFromID (root->account[i]->children, acc_id);
if (acc) return acc;
}
return NULL;
}
/********************************************************************\
* Fetch the root of the tree *
\********************************************************************/
@ -285,28 +293,6 @@ xaccGetAccountRoot (Account * acc)
return root;
}
/********************************************************************\
* Fetch an account, given only its ID number *
\********************************************************************/
Account *
xaccGetPeerAccountFromID ( Account *acc, int acc_id )
{
AccountGroup * root;
Account *peer_acc;
if (NULL == acc) return NULL;
if (-1 >= acc_id) return NULL;
/* first, find the root of the account group structure */
root = xaccGetAccountRoot (acc);
/* now search all acounts hanging off the root */
peer_acc = xaccGetAccountFromID (root, acc_id);
return peer_acc;
}
/********************************************************************\
* Fetch an account, given its name *
\********************************************************************/
@ -594,41 +580,45 @@ xaccGroupInsertAccount( AccountGroup *grp, Account *acc )
}
/********************************************************************\
* FIXME : this code needs to work differently.
\********************************************************************/
void
xaccRecomputeGroupBalance (AccountGroup *grp)
{
int i;
Account *acc;
char * default_currency;
if (!grp) return;
if (!(grp->account)) return;
acc = grp->account[0];
if (!acc) return;
default_currency = acc->currency;
grp->balance = 0.0;
for (i=0; i<grp->numAcc; i++) {
acc = grp->account[i];
/* first, get subtotals recursively */
if (acc->children) {
xaccRecomputeGroupBalance (acc->children);
if (!safe_strcmp (default_currency, acc->currency)) {
grp->balance += acc->children->balance;
}
xaccRecomputeGroupBalance (AccountGroup *grp) {
int i;
Account *acc;
const gnc_commodity * default_currency;
if (!grp) return;
if (!(grp->account)) return;
acc = grp->account[0];
if (!acc) return;
default_currency = acc->currency;
grp->balance = gnc_numeric_zero();
for (i=0; i<grp->numAcc; i++) {
acc = grp->account[i];
/* first, get subtotals recursively */
if (acc->children) {
xaccRecomputeGroupBalance (acc->children);
if (gnc_commodity_equiv(default_currency, acc->currency)) {
grp->balance =
gnc_numeric_add(grp->balance, acc->children->balance,
GNC_DENOM_AUTO, GNC_DENOM_LCD | GNC_RND_NEVER);
}
/* then add up accounts in this group */
xaccAccountRecomputeBalance (acc);
if (!safe_strcmp (default_currency, acc->currency)) {
grp->balance += acc->balance;
}
}
}
/* then add up accounts in this group */
xaccAccountRecomputeBalance (acc);
if (gnc_commodity_equiv(default_currency, acc->currency)) {
grp->balance =
gnc_numeric_add(grp->balance, acc->balance,
GNC_DENOM_AUTO, GNC_DENOM_LCD | GNC_RND_NEVER);
}
}
}
/********************************************************************\
@ -810,7 +800,8 @@ void
xaccMergeAccounts (AccountGroup *grp)
{
Account *acc_a, *acc_b;
int i, j, k;
int i, j;
GList *lp;
if (!grp) return;
@ -818,13 +809,19 @@ xaccMergeAccounts (AccountGroup *grp)
acc_a = grp->account[i];
for (j=i+1; j<grp->numAcc; j++) {
acc_b = grp->account[j];
if ((0 == safe_strcmp(acc_a->accountName, acc_b->accountName)) &&
(0 == safe_strcmp(acc_a->accountCode, acc_b->accountCode)) &&
(0 == safe_strcmp(acc_a->description, acc_b->description)) &&
(0 == safe_strcmp(acc_a->currency, acc_b->currency)) &&
(0 == safe_strcmp(acc_a->security, acc_b->security)) &&
(0 == safe_strcmp(acc_a->notes, acc_b->notes)) &&
(acc_a->type == acc_b->type)) {
if ((0 == safe_strcmp(xaccAccountGetName(acc_a),
xaccAccountGetName(acc_b))) &&
(0 == safe_strcmp(xaccAccountGetCode(acc_a),
xaccAccountGetCode(acc_b))) &&
(0 == safe_strcmp(xaccAccountGetDescription(acc_a),
xaccAccountGetDescription(acc_b))) &&
(gnc_commodity_equiv(xaccAccountGetCurrency(acc_a),
xaccAccountGetCurrency(acc_b))) &&
(gnc_commodity_equiv(xaccAccountGetSecurity(acc_a),
xaccAccountGetSecurity(acc_b))) &&
(0 == safe_strcmp(xaccAccountGetNotes(acc_a),
xaccAccountGetNotes(acc_b))) &&
(xaccAccountGetType(acc_a) == xaccAccountGetType(acc_b))) {
AccountGroup *ga, *gb;
@ -846,16 +843,14 @@ xaccMergeAccounts (AccountGroup *grp)
xaccMergeAccounts (ga);
/* consolidate transactions */
for (k=0; k<acc_b->numSplits; k++) {
Split *split;
split = acc_b->splits[k];
acc_b->splits[k] = NULL;
for(lp = acc_b->splits; lp; lp = lp->next) {
Split *split = (Split *) lp->data;
lp->data = NULL;
split->acc = NULL;
xaccAccountInsertSplit (acc_a, split);
}
/* free the account structure itself */
acc_b->numSplits = 0;
xaccFreeAccount (acc_b);
grp->account[j] = grp->account[grp->numAcc -1];
grp->account[grp->numAcc -1] = NULL;
@ -893,10 +888,16 @@ xaccGroupGetParentAccount (AccountGroup * grp)
}
double
DxaccGroupGetBalance (AccountGroup * grp)
{
return gnc_numeric_to_double(xaccGroupGetBalance(grp));
}
gnc_numeric
xaccGroupGetBalance (AccountGroup * grp)
{
if (!grp) return 0.0;
return (grp->balance);
if (!grp) return gnc_numeric_zero();
return grp->balance;
}
/********************************************************************\
@ -921,15 +922,16 @@ xaccGroupGetDepth (AccountGroup *grp)
\********************************************************************/
void
xaccSplitsBeginStagedTransactionTraversals (Split **splits)
xaccSplitsBeginStagedTransactionTraversals (GList *splits)
{
Transaction *trans;
Split **sptr;
GList *lp;
if (splits == NULL) return;
for (sptr = splits; *sptr != NULL; sptr++) {
trans = (*sptr)->parent;
for(lp = splits; lp; lp = lp->next) {
Split *s = (Split *) lp->data;
trans = s->parent;
if (trans != NULL)
trans->marker = 0;
}
@ -939,7 +941,6 @@ void
xaccAccountBeginStagedTransactionTraversals (Account *account)
{
if (account == NULL) return;
xaccSplitsBeginStagedTransactionTraversals(account->splits);
}
@ -986,23 +987,18 @@ xaccGroupBeginStagedTransactionTraversals (AccountGroup *grp)
numAcc = grp->numAcc;
for(i = 0; i < numAcc; i++) {
unsigned int n = 0;
Account *acc;
Split *s = NULL;
acc = xaccGroupGetAccount(grp, i);
Account *acc = xaccGroupGetAccount(grp, i);
GList *lp;
if (!acc) return;
/* recursively do sub-accounts */
xaccGroupBeginStagedTransactionTraversals(acc->children);
s = acc->splits[0];
while (s) {
for(lp = acc->splits; lp; lp = lp->next) {
Split *s = (Split *) lp->data;
Transaction *trans = s->parent;
trans->marker = 0;
n++;
s = acc->splits[n];
}
}
}
@ -1012,39 +1008,30 @@ xaccAccountStagedTransactionTraversal (Account *acc,
unsigned int stage,
int (*callback)(Transaction *t,
void *cb_data),
void *cb_data)
{
unsigned int n = 0;
Split *s = NULL;
void *cb_data) {
if (!acc) return 0;
s = acc->splits[0];
if (callback) {
int retval;
while (s) {
Transaction *trans = s->parent;
GList *lp;
for(lp = acc->splits; lp; lp = lp->next) {
Split *s = (Split *) lp->data;
Transaction *trans = s->parent;
if (trans && (trans->marker < stage)) {
int retval;
trans->marker = stage;
retval = callback(trans, cb_data);
if (retval) return retval;
}
n++;
s = acc->splits[n];
}
} else {
while (s) {
Transaction *trans = s->parent;
GList *lp;
for(lp = acc->splits; lp; lp = lp->next) {
Split *s = (Split *) lp->data;
Transaction *trans = s->parent;
if (trans && (trans->marker < stage)) {
trans->marker = stage;
}
n++;
s = acc->splits[n];
}
}
return 0;
}
@ -1080,4 +1067,97 @@ xaccGroupStagedTransactionTraversal(AccountGroup *grp,
return 0;
}
/************************* END OF FILE ********************************/
/********************************************************************\
\********************************************************************/
gboolean
xaccGroupVisitUnvisitedTransactions(AccountGroup *g,
gboolean (*proc)(Transaction *t,
void *data),
void *data,
GHashTable *visited_txns) {
Account **accounts = NULL;
gboolean keep_going = TRUE;
if(!g) return(FALSE);
if(!proc) return(FALSE);
if(!visited_txns) return(FALSE);
accounts = xaccGetAccounts(g);
if(!accounts) return(FALSE);
while(*accounts && keep_going) {
Account *acc = *accounts;
keep_going =
xaccAccountVisitUnvisitedTransactions(acc, proc, data, visited_txns);
if(keep_going) accounts++;
}
return(keep_going);
}
gboolean
xaccGroupForEachTransaction(AccountGroup *g,
gboolean (*proc)(Transaction *t, void *data),
void *data) {
GHashTable *visited_txns = NULL;
gboolean result = FALSE;
if(!g) return(FALSE);
if(!proc) return(FALSE);
visited_txns = guid_hash_table_new();
if(visited_txns) {
result = xaccGroupVisitUnvisitedTransactions(g, proc, data, visited_txns);
}
/* cleanup */
if(visited_txns) g_hash_table_destroy(visited_txns);
return(result);
}
/********************************************************************\
\********************************************************************/
GSList *
xaccGroupMapAccounts(AccountGroup *grp,
gpointer (*thunk)(Account *a, void *data),
gpointer data) {
Account **accts;
GSList *result = NULL;
if(!grp) return(NULL);
if(!thunk) return(NULL);
accts = grp->account;
if(!accts) return(NULL);
while(*accts) {
gpointer thunk_result = thunk(*accts, data);
if(thunk_result) result = g_slist_prepend(result, thunk_result);
accts++;
}
return(g_slist_reverse(result));
}
gpointer
xaccGroupForEachAccountDeeply(AccountGroup *grp,
gpointer (*thunk)(Account *a, void *data),
gpointer data) {
Account **accts;
if(!grp) return(NULL);
if(!thunk) return(NULL);
accts = grp->account;
if(!accts) return(NULL);
while(*accts) {
Account *acc = *accts;
gpointer result = thunk(acc, data);
if(result) return(result);
result = xaccGroupForEachAccountDeeply(acc->children, thunk, data);
if(result) return(result);
accts++;
}
return(NULL);
}

View File

@ -25,6 +25,8 @@
#ifndef __XACC_ACCOUNT_GROUP_H__
#define __XACC_ACCOUNT_GROUP_H__
#include <glib.h>
#include "config.h"
#include "gnc-common.h"
@ -113,16 +115,6 @@ Account ** xaccGetAccounts (AccountGroup *grp);
int xaccFillInAccounts ( AccountGroup *root, Account **arr );
/*
* The xaccGetAccountFromID() subroutine fetches the account
* with the indicated account id from the collection of accounts
* in the indicated AccountGroup. It returns NULL if the
* account was not found.
*
* The xaccGetPeerAccountFromID() subroutine fetches the account
* with the indicated account id from the collection of accounts
* in the same AccountGroup anchor group. It returns NULL if the
* account was not found.
*
* The xaccGetAccountFromName() subroutine fetches the
* account by name from the collection of accounts
* in the indicated AccountGroup group. It returns NULL if the
@ -142,8 +134,6 @@ int xaccFillInAccounts ( AccountGroup *root, Account **arr );
* names using the given separator.
*/
Account *xaccGetAccountFromID (AccountGroup *, int);
Account *xaccGetPeerAccountFromID (Account *, int);
Account *xaccGetAccountFromName (AccountGroup *, const char *);
Account *xaccGetAccountFromFullName (AccountGroup *,
const char *name,
@ -165,7 +155,9 @@ void xaccRecomputeGroupBalance (AccountGroup *);
* of all the children in this group.
*/
double xaccGroupGetBalance (AccountGroup *);
/* deprecated double API will go away */
double DxaccGroupGetBalance (AccountGroup *);
gnc_numeric xaccGroupGetBalance (AccountGroup *);
/*
* The xaccGetAccountRoot () subroutine will find the topmost
@ -205,6 +197,16 @@ char * xaccAccountGetNextChildCode (Account *acc, int num_digits);
void xaccGroupAutoCode (AccountGroup *grp, int num_digits);
void xaccGroupDepthAutoCode (AccountGroup *grp);
/* if the function returns null for a given item, it won't show up in
the result list */
GSList *xaccGroupMapAccounts(AccountGroup *grp,
gpointer (*thunk)(Account *a, void *data),
gpointer data);
gpointer xaccGroupForEachAccountDeeply(AccountGroup *grp,
gpointer (*thunk)(Account *a, void *data),
gpointer data);
gboolean xaccGroupEqual(AccountGroup *a, AccountGroup *b, gboolean check_guids);
#ifndef SWIG
@ -262,7 +264,7 @@ void xaccGroupDepthAutoCode (AccountGroup *grp);
*/
void xaccGroupBeginStagedTransactionTraversals(AccountGroup *grp);
void xaccSplitsBeginStagedTransactionTraversals(Split **splits);
void xaccSplitsBeginStagedTransactionTraversals(GList *splits);
void xaccAccountBeginStagedTransactionTraversals(Account *account);
void xaccAccountsBeginStagedTransactionTraversals (Account **accounts);
@ -314,6 +316,41 @@ int xaccAccountStagedTransactionTraversal(Account *a,
void *data),
void *data);
#endif
/* Traverse all of the transactions in the given account group.
Continue processing IFF proc does not return FALSE. This function
does not descend recursively to traverse transactions in the
children of the accounts in the group.
Proc will be called exactly once for each transaction that is
pointed to by at least one split in an account in the account
group.
Note too, that if you call this function on two separate account
groups and those accounts groups share transactions, proc will be
called once per account on the shared transactions.
The result of this function will not be FALSE IFF every relevant
transaction was traversed exactly once. */
gboolean
xaccGroupForEachTransaction(AccountGroup *g,
gboolean (*proc)(Transaction *t, void *data),
void *data);
/* Visit every transaction in the account that hasn't already been
visited exactly once. visited_txns must be a hash table created
via guid_hash_table_new() and is the authority about which
transactions have already been visited. Further, when this
procedure returns, visited_txns will have been modified to reflect
all the newly visited transactions.
The result of this function will not be FALSE IFF every relevant
transaction was traversed exactly once. */
gboolean
xaccGroupVisitUnvisitedTransactions(AccountGroup *g,
gboolean (*proc)(Transaction *t, void *data),
void *data,
GHashTable *visited_txns);
#endif /* SWIG */
#endif /* __XACC_ACCOUNT_GROUP_H__ */

View File

@ -40,7 +40,7 @@
#include "BackendP.h"
#include "GNCId.h"
#include "Transaction.h"
#include "gnc-numeric.h"
/** STRUCTS *********************************************************/
struct _account_group {
@ -56,7 +56,7 @@ struct _account_group {
Backend *backend; /* persistant storage backend */
/* cached parameters */
double balance;
gnc_numeric balance;
};
#endif /* __XACC_ACCOUNT_GROUP_P_H__ */

View File

@ -7,14 +7,12 @@ lib_LTLIBRARIES = libgncengine.la
# Build hell from main.c and libhello.la
libgncengine_la_SOURCES = \
AccInfo.c \
Account.c \
Backend.c \
DateUtils.c \
FileIO.c \
Group.c \
Query.c \
Queue.c \
Scrub.c \
Session.c \
Transaction.c \
@ -23,14 +21,18 @@ libgncengine_la_SOURCES = \
util.c \
GNCId.c \
guid.c \
io-gncbin-r.c \
io-gncxml-r.c \
io-gncxml-w.c \
md5.c \
kvp_frame.c
kvp_frame.c \
gnc-commodity.c\
gnc-numeric.c \
gnc-engine.c
libgncengine_la_LDFLAGS = -version-info 1:1:1
libgncengine_la_LDFLAGS = -version-info 2:1:1
noinst_HEADERS = \
AccInfo.h \
AccInfoP.h \
Account.h \
AccountP.h \
BackendP.h \
@ -42,7 +44,6 @@ noinst_HEADERS = \
Group.h \
GroupP.h \
Query.h \
Queue.h \
Scrub.h \
Session.h \
TransLog.h \
@ -51,17 +52,25 @@ noinst_HEADERS = \
date.h \
gnc-common.h \
guid.h \
io-gncbin.h \
io-gncxml.h \
md5.h \
util.h \
kvp_frame.h
kvp_frame.h \
gnc-commodity.h \
gnc-numeric.h \
gnc-engine.h
EXTRA_DIST = \
.cvsignore \
README.query-api \
README.gnc-numeric \
design.txt \
extensions.txt \
kvp_doc.txt
CFLAGS = @CFLAGS@ ${GLIB_CFLAGS}
CFLAGS = @CFLAGS@ ${GLIB_CFLAGS} ${GNOME_XML_CFLAGS}
LDADD = ${GNOME_XML_LIB}
INCLUDES = -I..

View File

@ -32,6 +32,7 @@
#include <assert.h>
#include "gnc-common.h"
#include "gnc-numeric.h"
#include "TransactionP.h"
#include "Transaction.h"
#include "Account.h"
@ -546,7 +547,7 @@ split_cmp_func(sort_type_t how, gconstpointer ga, gconstpointer gb) {
unsigned long n1;
unsigned long n2;
char *da, *db;
double fa, fb;
gnc_numeric fa, fb;
if (sa && !sb) return -1;
if (!sa && sb) return 1;
@ -565,7 +566,7 @@ split_cmp_func(sort_type_t how, gconstpointer ga, gconstpointer gb) {
switch(how) {
case BY_STANDARD:
return xaccSplitDateOrder(&sa, &sb);
return xaccSplitDateOrder(sa, sb);
break;
case BY_DATE:
@ -657,17 +658,9 @@ split_cmp_func(sort_type_t how, gconstpointer ga, gconstpointer gb) {
break;
case BY_AMOUNT:
fa = (sa->damount) * (sa->share_price);
fb = (sb->damount) * (sb->share_price);
if (fa < fb) {
return -1;
}
else if (fa > fb) {
return +1;
}
else {
return 0;
}
fa = sa->value;
fb = sb->value;
return gnc_numeric_compare(fa, fb);
break;
case BY_RECONCILE:
@ -773,8 +766,6 @@ xaccQueryGetSplits(Query * q) {
GList * or_ptr, * and_ptr, * mptr;
Account ** all_accts, ** ptr;
Account * current;
Split ** splits;
Split ** sptr;
QueryTerm * qt;
int total_splits_checked = 0;
@ -835,12 +826,13 @@ xaccQueryGetSplits(Query * q) {
}
if(acct_ok) {
splits = xaccAccountGetSplitList(current);
GList *lp;
/* iterate over splits */
for(sptr = splits; *sptr; sptr++) {
if(xaccQueryCheckSplit(q, *sptr)) {
matching_splits = g_list_prepend(matching_splits, *sptr);
for(lp = xaccAccountGetSplitList(current); lp; lp = lp->next) {
Split *s = (Split *) lp->data;
if(xaccQueryCheckSplit(q, s)) {
matching_splits = g_list_prepend(matching_splits, s);
split_count++;
}
total_splits_checked++;
@ -882,30 +874,32 @@ xaccQueryGetSplits(Query * q) {
split_count = q->max_splits;
}
/* convert the g_list into a split array. */
splits = g_new0(Split *, split_count+1);
posn = 0;
for(mptr = matching_splits; mptr; mptr=mptr->next) {
splits[posn] = mptr->data;
posn++;
{ /* convert the g_list into a split array. */
Split **splits = g_new0(Split *, split_count+1);
posn = 0;
for(mptr = matching_splits; mptr; mptr=mptr->next) {
splits[posn] = mptr->data;
posn++;
}
splits[split_count] = NULL;
g_list_free(matching_splits);
gettimeofday(&end, NULL);
PINFO("elapsed time = %e ms\n",
(end.tv_sec - start.tv_sec)*1000.0 +
(end.tv_usec - start.tv_usec)/1000.0);
PINFO("%d splits checked, %d splits matched.\n",
total_splits_checked, split_count);
q->changed = 0;
g_free(q->split_list);
q->split_list = splits;
return splits;
}
splits[split_count] = NULL;
g_list_free(matching_splits);
gettimeofday(&end, NULL);
PINFO("elapsed time = %e ms\n",
(end.tv_sec - start.tv_sec)*1000.0 +
(end.tv_usec - start.tv_usec)/1000.0);
PINFO("%d splits checked, %d splits matched.\n",
total_splits_checked, split_count);
q->changed = 0;
g_free(q->split_list);
q->split_list = splits;
return splits;
}
@ -1095,8 +1089,8 @@ xaccQueryAddMemoMatch(Query * q, char * matchstring,
void
xaccQueryAddDateMatch(Query * q,
int sday, int smonth, int syear,
int eday, int emonth, int eyear,
int use_start, int sday, int smonth, int syear,
int use_end, int eday, int emonth, int eyear,
QueryOp op) {
Query * qs = xaccMallocQuery();
QueryTerm * qt = g_new0(QueryTerm, 1);
@ -1105,7 +1099,9 @@ xaccQueryAddDateMatch(Query * q,
qt->p = & xaccDateMatchPredicate;
qt->sense = 1;
qt->data.type = PD_DATE;
qt->data.date.use_start = use_start;
qt->data.date.start = gnc_dmy2timespec(sday, smonth, syear);
qt->data.date.use_end = use_end;
qt->data.date.end = gnc_dmy2timespec(eday, emonth, eyear);
xaccInitQuery(qs, qt);
@ -1129,7 +1125,9 @@ xaccQueryAddDateMatch(Query * q,
void
xaccQueryAddDateMatchTS(Query * q,
int use_start,
Timespec sts,
int use_end,
Timespec ets,
QueryOp op) {
Query * qs = xaccMallocQuery();
@ -1139,6 +1137,8 @@ xaccQueryAddDateMatchTS(Query * q,
qt->p = & xaccDateMatchPredicate;
qt->sense = 1;
qt->data.type = PD_DATE;
qt->data.date.use_start = use_start;
qt->data.date.use_end = use_end;
qt->data.date.start = sts;
qt->data.date.end = ets;
@ -1163,7 +1163,9 @@ xaccQueryAddDateMatchTS(Query * q,
void
xaccQueryAddDateMatchTT(Query * q,
int use_start,
time_t stt,
int use_end,
time_t ett,
QueryOp op) {
Query * qs = xaccMallocQuery();
@ -1180,7 +1182,9 @@ xaccQueryAddDateMatchTT(Query * q,
qt->p = & xaccDateMatchPredicate;
qt->sense = 1;
qt->data.type = PD_DATE;
qt->data.type = PD_DATE;
qt->data.date.use_start = use_start;
qt->data.date.use_end = use_end;
qt->data.date.start = sts;
qt->data.date.end = ets;
@ -1309,15 +1313,17 @@ xaccQueryAddActionMatch(Query * q, char * matchstring, int case_sens,
/********************************************************************
* xaccQueryAddAmountMatch
* DxaccQueryAddAmountMatch
* Add a value filter to an existing query.
* FIXME
********************************************************************/
void
xaccQueryAddAmountMatch(Query * q, double amt,
amt_match_sgn_t amt_sgn,
amt_match_t how,
QueryOp op) {
DxaccQueryAddAmountMatch(Query * q, double amt,
amt_match_sgn_t amt_sgn,
amt_match_t how,
QueryOp op) {
Query * qs = xaccMallocQuery();
QueryTerm * qt = g_new0(QueryTerm, 1);
Query * qr;
@ -1345,12 +1351,13 @@ xaccQueryAddAmountMatch(Query * q, double amt,
/********************************************************************
* xaccQueryAddSharePriceMatch
* DxaccQueryAddSharePriceMatch
* Add a share-price filter to an existing query.
* FIXME
********************************************************************/
void
xaccQueryAddSharePriceMatch(Query * q, double amt,
DxaccQueryAddSharePriceMatch(Query * q, double amt,
amt_match_t how,
QueryOp op) {
Query * qs = xaccMallocQuery();
@ -1378,13 +1385,15 @@ xaccQueryAddSharePriceMatch(Query * q, double amt,
xaccFreeQuery(qr);
}
/********************************************************************
* xaccQueryAddSharesMatch
* DxaccQueryAddSharesMatch
* Add a share-price filter to an existing query.
* FIXME
********************************************************************/
void
xaccQueryAddSharesMatch(Query * q, double amt,
DxaccQueryAddSharesMatch(Query * q, double amt,
amt_match_t how,
QueryOp op) {
Query * qs = xaccMallocQuery();
@ -1714,18 +1723,6 @@ xaccMemoMatchPredicate(Split * s, PredicateData * pd) {
}
/*******************************************************************
* xaccMiscMatchPredicate
* *** Bill, please complete! ***
*******************************************************************/
#if 0
static int
xaccMiscMatchPredicate(Split * s, PredicateData * pd) {
return 0;
}
#endif
/*******************************************************************
* xaccAmountMatchPredicate
*******************************************************************/
@ -1736,7 +1733,7 @@ xaccAmountMatchPredicate(Split * s, PredicateData * pd) {
assert(s && pd);
assert(pd->type == PD_AMOUNT);
splitamt = xaccSplitGetValue(s);
splitamt = DxaccSplitGetValue(s);
switch(pd->amount.amt_sgn) {
case AMT_SGN_MATCH_CREDIT:
@ -1770,7 +1767,7 @@ xaccSharePriceMatchPredicate(Split * s, PredicateData * pd) {
if((type != STOCK) && (type != MUTUAL)) {
return 0;
}
splitamt = xaccSplitGetSharePrice(s);
splitamt = DxaccSplitGetSharePrice(s);
return value_match_predicate(splitamt, pd);
}
@ -1795,7 +1792,7 @@ xaccSharesMatchPredicate(Split * s, PredicateData * pd) {
return 0;
}
splitamt = xaccSplitGetShareAmount(s);
splitamt = DxaccSplitGetShareAmount(s);
return value_match_predicate(splitamt, pd);
}
@ -1812,9 +1809,20 @@ xaccDateMatchPredicate(Split * s, PredicateData * pd) {
assert(pd->type == PD_DATE);
xaccTransGetDateTS(xaccSplitGetParent(s), &transtime);
return ((transtime.tv_sec >= pd->date.start.tv_sec) &&
(transtime.tv_sec <= pd->date.end.tv_sec));
if(pd->date.use_start && pd->date.use_end) {
return ((transtime.tv_sec >= pd->date.start.tv_sec) &&
(transtime.tv_sec <= pd->date.end.tv_sec));
}
else if(pd->date.use_start) {
return ((transtime.tv_sec >= pd->date.start.tv_sec));
}
else if(pd->date.use_end) {
return ((transtime.tv_sec <= pd->date.end.tv_sec));
}
else {
return 1;
}
}
/*******************************************************************

View File

@ -71,7 +71,9 @@ typedef struct _querystruct Query;
typedef struct {
pd_type_t type;
int use_start;
Timespec start;
int use_end;
Timespec end;
} DatePredicateData;
@ -158,22 +160,24 @@ void xaccQueryAddNumberMatch(Query * q, char * matchstring,
int case_sens, int use_regexp, QueryOp op);
void xaccQueryAddActionMatch(Query * q, char * matchstring,
int case_sens, int use_regexp, QueryOp op);
void xaccQueryAddAmountMatch(Query * q, double amount,
amt_match_sgn_t amt_sgn,
amt_match_t how, QueryOp op);
void xaccQueryAddSharePriceMatch(Query * q, double amount,
amt_match_t how, QueryOp op);
void xaccQueryAddSharesMatch(Query * q, double amount,
amt_match_t how, QueryOp op);
void DxaccQueryAddAmountMatch(Query * q, double amount,
amt_match_sgn_t amt_sgn,
amt_match_t how, QueryOp op);
void DxaccQueryAddSharePriceMatch(Query * q, double amount,
amt_match_t how, QueryOp op);
void DxaccQueryAddSharesMatch(Query * q, double amount,
amt_match_t how, QueryOp op);
void xaccQueryAddDateMatch(Query * q,
int syear, int smonth, int sday,
int eyear, int emonth, int eday,
int use_start, int syear, int smonth, int sday,
int use_end, int eyear, int emonth, int eday,
QueryOp op);
void xaccQueryAddDateMatchTS(Query * q,
Timespec sts, Timespec ets,
int use_start, Timespec sts,
int use_end, Timespec ets,
QueryOp op);
void xaccQueryAddDateMatchTT(Query * q,
time_t stt, time_t ett,
int use_start, time_t stt,
int use_end, time_t ett,
QueryOp op);
void xaccQueryAddMemoMatch(Query * q, char * matchstring,
int case_sens, int use_regexp, QueryOp op);

View File

@ -73,39 +73,35 @@ xaccAccountTreeScrubOrphans (Account *acc)
#endif
void
xaccAccountScrubOrphans (Account *acc)
{
int i=0;
Split *split, **slist;
Transaction *trans;
Account * parent;
xaccAccountScrubOrphans (Account *acc) {
GList *slp;
Transaction *trans;
Account * parent;
PINFO ("Looking for orphans in account %s \n", xaccAccountGetName(acc));
for(slp = xaccAccountGetSplitList(acc); slp; slp = slp->next) {
Split *split = (Split *) slp->data;
Split * tsplit;
int j = 0;
PINFO ("Looking for orphans in account %s \n", xaccAccountGetName(acc));
slist = xaccAccountGetSplitList (acc);
split = slist[0];
while (split) {
Split * s;
int j = 0;
trans = xaccSplitGetParent (split);
s = xaccTransGetSplit (trans, 0);
while (s) {
parent = xaccSplitGetAccount (s);
if (!parent) {
Account *orph;
DEBUG ("Found an orphan \n");
/* OK, we found an orphan. Put it in an orphan account. */
orph = GetOrMakeAccount (acc, trans, ORPHAN_STR);
xaccAccountBeginEdit (orph, 1);
xaccAccountInsertSplit (orph, s);
xaccAccountCommitEdit (orph);
}
j++;
s = xaccTransGetSplit (trans, j);
trans = xaccSplitGetParent (split);
tsplit = xaccTransGetSplit (trans, 0);
while (tsplit) {
parent = xaccSplitGetAccount (tsplit);
if (!parent) {
Account *orph;
DEBUG ("Found an orphan \n");
/* OK, we found an orphan. Put it in an orphan account. */
orph = GetOrMakeAccount (acc, trans, ORPHAN_STR);
xaccAccountBeginEdit (orph);
xaccAccountInsertSplit (orph, tsplit);
xaccAccountCommitEdit (orph);
}
i++; split = slist[i];
}
j++;
tsplit = xaccTransGetSplit (trans, j);
}
}
}
/* ================================================================ */
@ -134,21 +130,17 @@ xaccAccountTreeScrubImbalance (Account *acc)
#endif
void
xaccAccountScrubImbalance (Account *acc)
{
int i=0;
Split *split, **slist;
Transaction *trans;
xaccAccountScrubImbalance (Account *acc) {
GList *slp;
PINFO ("Looking for imbalance in account %s \n", xaccAccountGetName(acc));
slist = xaccAccountGetSplitList (acc);
split = slist[0];
while (split) {
double imbalance;
trans = xaccSplitGetParent (split);
for(slp = xaccAccountGetSplitList(acc); slp; slp = slp->next) {
Split *split = (Split *) slp->data;
Transaction *trans = xaccSplitGetParent(split);
double imbalance;
imbalance = xaccTransGetImbalance (trans);
imbalance = DxaccTransGetImbalance (trans);
if (!(DEQ (imbalance, 0.0))) {
Split *splat;
Account *orph;
@ -158,16 +150,15 @@ xaccAccountScrubImbalance (Account *acc)
/* put split into account before setting split value */
splat = xaccMallocSplit();
xaccAccountBeginEdit (orph, 1);
xaccAccountBeginEdit (orph);
xaccAccountInsertSplit (orph, splat);
xaccAccountCommitEdit (orph);
xaccTransBeginEdit (trans, 1);
xaccSplitSetValue (splat, -imbalance);
DxaccSplitSetValue (splat, -imbalance);
xaccTransAppendSplit (trans, splat);
xaccTransCommitEdit (trans);
}
i++; split = slist[i];
}
}
@ -177,16 +168,17 @@ static Account *
GetOrMakeAccount (Account *peer, Transaction *trans, const char *name_root)
{
char * accname;
const char * currency;
const gnc_commodity * currency;
Account * acc;
AccountGroup *root;
/* build the account name */
currency = xaccTransFindCommonCurrency (trans);
accname = alloca (strlen (name_root) + strlen (currency) + 2);
accname = alloca (strlen (name_root) +
strlen (gnc_commodity_get_mnemonic(currency)) + 2);
strcpy (accname, name_root);
strcat (accname, "-");
strcat (accname, currency);
strcat (accname, gnc_commodity_get_mnemonic(currency));
/* see if we've got one of these going already ... */
acc = xaccGetPeerAccountFromName (peer, accname);
@ -194,7 +186,7 @@ GetOrMakeAccount (Account *peer, Transaction *trans, const char *name_root)
/* guess not. We'll have to build one */
acc = xaccMallocAccount ();
xaccAccountBeginEdit (acc, 1);
xaccAccountBeginEdit (acc);
xaccAccountSetName (acc, accname);
xaccAccountSetCurrency (acc, currency);
xaccAccountSetType (acc, BANK);

View File

@ -40,7 +40,6 @@
#include "BackendP.h"
#include "FileIO.h"
#include "FileIOP.h"
#include "Group.h"
#include "Session.h"
#include "util.h"
@ -59,6 +58,11 @@ struct _session {
*/
int errtype;
/* FIXME: This is a hack. I'm trying to move us away from static
global vars. This may be a temp fix if we decide to integrate
FileIO errors into Session errors... */
GNCFileIOError last_file_err;
/* ---------------------------------------------------- */
/* teh following struct members apply only for file-io */
/* the fully-resolved path to the file */
@ -93,6 +97,7 @@ xaccInitSession (Session *sess)
if (!sess) return;
sess->topgroup = NULL;
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
sess->sessionid = NULL;
sess->fullpath = NULL;
sess->lockfile = NULL;
@ -116,6 +121,14 @@ xaccSessionGetError (Session * sess)
/* ============================================================== */
GNCFileIOError
xaccSessionGetFileError (Session * sess) {
if (!sess) return ERR_FILEIO_MISC;
return sess->last_file_err;
}
/* ============================================================== */
AccountGroup *
xaccSessionGetGroup (Session *sess)
{
@ -150,42 +163,41 @@ xaccSessionGetFilePath (Session *sess)
/* ============================================================== */
AccountGroup *
xaccSessionBegin (Session *sess, const char * sid)
{
AccountGroup *retval;
gboolean
xaccSessionBegin (Session *sess, const char * sid) {
if (!sess) return NULL;
if(!sess) return FALSE;
if(!sid) return FALSE;
/* clear the error condition of previous errors */
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
/* check to see if this session is already open */
if (sess->sessionid) {
sess->errtype = ETXTBSY;
return NULL;
return FALSE;
}
/* seriously invalid */
if (!sid) {
sess->errtype = EINVAL;
return NULL;
return FALSE;
}
/* check to see if this is a type we know how to handle */
if (strncmp (sid, "file:", 5)) {
if(strncmp(sid, "file:", 5) != 0) {
sess->errtype = ENOSYS;
return NULL;
return FALSE;
}
/* add 5 to space past 'file:' */
retval = xaccSessionBeginFile (sess, sid+5, NULL);
return retval;
return xaccSessionBeginFile(sess, sid+5, NULL);
}
/* ============================================================== */
#if 0
static AccountGroup *
xaccSessionBeginSQL (Session *sess, const char * dbname)
{
@ -194,7 +206,7 @@ xaccSessionBeginSQL (Session *sess, const char * dbname)
if (!sess) return NULL;
// #define SQLHACK
/* #define SQLHACK */
#ifdef SQLHACK
{
/* for testing the sql, just a hack, remove later ... */
@ -208,12 +220,13 @@ extern Backend * pgendNew (void);
if (be && be->session_begin) {
grp = (be->session_begin) (sess, dbname);
}
// comment out until testing done, else clobber file ...
// sess->topgroup = grp;
/* comment out until testing done, else clobber file ...*/
/* sess->topgroup = grp; */
xaccGroupSetBackend (sess->topgroup, be);
return (sess->topgroup);
}
#endif
/* ============================================================== */
@ -285,28 +298,27 @@ xaccSessionGetFileLock (Session *sess)
/* ============================================================== */
AccountGroup *
gboolean
xaccSessionBeginFile (Session *sess, const char * filefrag,
SessionLockFailHandler handler)
{
struct stat statbuf;
int rc;
SessionLockFailHandler handler) {
if (!sess) return NULL;
if(!sess) return FALSE;
if(!filefrag) return FALSE;
/* clear the error condition of previous errors */
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
/* check to see if this session is already open */
if (sess->sessionid) {
sess->errtype = ETXTBSY;
return NULL;
return FALSE;
}
/* seriously invalid */
if (!filefrag) {
sess->errtype = EINVAL;
return NULL;
return FALSE;
}
/* ---------------------------------------------------- */
@ -315,7 +327,7 @@ xaccSessionBeginFile (Session *sess, const char * filefrag,
sess->fullpath = xaccResolveFilePath (filefrag);
if (! (sess->fullpath)) {
sess->errtype = ERANGE;
return NULL; /* ouch */
return FALSE; /* ouch */
}
/* Store the sessionid URL also ... */
@ -332,29 +344,75 @@ xaccSessionBeginFile (Session *sess, const char * filefrag,
g_free (sess->sessionid); sess->sessionid = NULL;
g_free (sess->fullpath); sess->fullpath = NULL;
g_free (sess->lockfile); sess->lockfile = NULL;
return NULL;
return FALSE;
}
}
/* ---------------------------------------------------- */
/* OK, if we've gotten this far, then we've succesfully obtained
* an atomic lock on the file. Go read the file contents if it
* exists. */
sess->errtype = 0;
sess->topgroup = NULL;
rc = stat (sess->fullpath, &statbuf);
if (!rc) {
sess->topgroup = xaccReadAccountGroupFile (sess->fullpath);
}
return TRUE;
}
#ifdef SQLHACK
/* for testing the sql, just a hack, remove later ... */
/* this should never ever appear here ... */
xaccSessionBeginSQL (sess, "postgres://localhost/gnc_bogus");
/* for testing the sql, just a hack, remove later ... */
/* this should never ever appear here ... */
xaccSessionBeginSQL (sess, "postgres://localhost/gnc_bogus");
#endif
/* ============================================================== */
gboolean
xaccSessionLoad(Session *sess) {
if(!sess) return FALSE;
if(!sess->sessionid) return FALSE;
if(strncmp(sess->sessionid, "file:", 5) == 0) {
/* file: */
if(!sess->lockfile) {
sess->errtype = ENOLCK;
return FALSE;
}
/* At this point, we should have a valid session id and a lock on
the file. */
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
sess->topgroup = xaccReadAccountGroupFile (sess->fullpath,
&(sess->last_file_err));
if(!sess->topgroup || (sess->last_file_err != ERR_FILEIO_NONE)) {
sess->errtype = EIO;
return FALSE;
}
return TRUE;
} else {
sess->errtype = ENOSYS;
return FALSE;
}
}
/* ============================================================== */
gboolean
xaccSessionSaveMayClobberData(Session *s) {
/* FIXME: Make sure this doesn't need more sophisticated semantics
in the face of special file, devices, pipes, symlinks, etc... */
struct stat statbuf;
if(!s) return FALSE;
if(!s->fullpath) return FALSE;
if(stat(s->fullpath, &statbuf) == 0) return TRUE;
return FALSE;
#ifdef SQLHACK
/* for testing the sql, just a hack, remove later ... */
/* this should never ever appear here ... */
xaccSessionBeginSQL (sess, "postgres://localhost/gnc_bogus");
#endif
return (sess->topgroup);
}
/* ============================================================== */
@ -367,6 +425,7 @@ xaccSessionSave (Session *sess)
/* if the fullpath doesn't exist, either the user failed to initialize,
* or the lockfile was never obtained ... either way, we can't write. */
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
if (!(sess->fullpath)) {
sess->errtype = ENOLCK;
@ -374,12 +433,11 @@ xaccSessionSave (Session *sess)
}
if (sess->topgroup) {
int error = xaccWriteAccountGroupFile (sess->fullpath, sess->topgroup);
if (error < 0)
sess->errtype = errno;
} else {
/* hmm ... no topgroup means delete file */
unlink (sess->fullpath);
gboolean write_ok = xaccWriteAccountGroupFile (sess->fullpath,
sess->topgroup,
TRUE,
&(sess->last_file_err));
if (!write_ok) sess->errtype = errno;
}
}
@ -390,6 +448,7 @@ xaccSessionEnd (Session *sess)
{
if (!sess) return;
sess->errtype = 0;
sess->last_file_err = ERR_FILEIO_NONE;
if (sess->linkfile) unlink (sess->linkfile);
if (0 < sess->lockfd) close (sess->lockfd);

View File

@ -49,6 +49,7 @@
#define __XACC_SESSION_H__
#include "Group.h"
#include "FileIO.h"
/** STRUCTS *********************************************************/
typedef struct _session Session;
@ -122,10 +123,7 @@ void xaccSessionDestroy (Session *);
* The xaccSessionSave() method will commit all changes that have been
* made to the top-level account group. In the current
* implementation, this is nothing more than a write to the file of
* the current AccountGroup of the session. If the current
* AccountGroup is NULL, then the file will be deleted. This
* routine will never release the lock on the file under any
* circustances.
* the current AccountGroup of the session.
*
* The xaccSessionEnd() method will release the session lock. It will *not*
* save the account group to a file. Thus, this method acts as an "abort"
@ -175,14 +173,29 @@ void xaccSessionDestroy (Session *);
typedef gboolean (*SessionLockFailHandler)(const char *file);
AccountGroup * xaccSessionBegin (Session *, const char * sessionid);
AccountGroup * xaccSessionBeginFile (Session *, const char * filename,
SessionLockFailHandler handler);
/* These do not load anything. */
gboolean xaccSessionBegin(Session *, const char * sessionid);
gboolean xaccSessionBeginFile(Session *, const char * filename,
SessionLockFailHandler handler);
/* Loads the account group indicated by SessionBegin. */
gboolean xaccSessionLoad(Session *);
int xaccSessionGetError (Session *);
/* FIXME: This is a hack. I'm trying to move us away from static
global vars. This may be a temp fix if we decide to integrate
FileIO errors into Session errors... This just returns the last
FileIO error, but it doesn't clear it. */
GNCFileIOError xaccSessionGetFileError (Session *);
AccountGroup * xaccSessionGetGroup (Session *);
void xaccSessionSetGroup (Session *, AccountGroup *topgroup);
char * xaccSessionGetFilePath (Session *);
/* FIXME: This isn't as thorough as we might want it to be... */
gboolean xaccSessionSaveMayClobberData(Session *s);
void xaccSessionSave (Session *);
void xaccSessionEnd (Session *);

View File

@ -210,7 +210,7 @@ xaccTransWriteLog (Transaction *trans, char flag)
/* use tab-separated fields */
fprintf (trans_log, "%c %p/%p %s %s %s %s %s " \
"%s %s %s %c %10.6f %10.6f %s\n",
"%s %s %s %c %Ld/%Ld %Ld/%Ld %s\n",
flag,
trans, split, /* trans+split make up unique id */
dnow,
@ -222,8 +222,10 @@ xaccTransWriteLog (Transaction *trans, char flag)
split->memo,
split->action,
split->reconciled,
split->damount,
split->share_price,
gnc_numeric_num(split->damount),
gnc_numeric_denom(split->damount),
gnc_numeric_num(split->value),
gnc_numeric_denom(split->value),
drecn
);
free (drecn);
@ -255,7 +257,7 @@ xaccSplitAsString(Split *split, const char prefix[]) {
size_t result_size;
FILE *stream = open_memstream(&result, &result_size);
const char *split_memo = xaccSplitGetMemo(split);
const double split_value = xaccSplitGetValue(split);
const double split_value = DxaccSplitGetValue(split);
Account *split_dest = xaccSplitGetAccount(split);
const char *dest_name =
split_dest ? xaccAccountGetName(split_dest) : NULL;
@ -281,7 +283,7 @@ xaccTransAsString(Transaction *txn, const char prefix[]) {
const char *num = xaccTransGetNum(txn);
const char *desc = xaccTransGetDescription(txn);
const char *memo = xaccSplitGetMemo(xaccTransGetSplit(txn, 0));
const double total = xaccSplitGetValue(xaccTransGetSplit(txn, 0));
const double total = DxaccSplitGetValue(xaccTransGetSplit(txn, 0));
assert(stream);

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@
#include <time.h>
#include "gnc-common.h"
#include "gnc-commodity.h"
#include "kvp_frame.h"
#include "GNCId.h"
#include "date.h"
@ -78,6 +79,11 @@ int xaccConfigGetForceDoubleEntry (void);
*/
Transaction * xaccMallocTransaction (void);
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb,
gboolean check_guids,
gboolean check_splits);
/* The xaccTransDestroy() method will remove all
* of the splits from each of their accounts, free the memory
* associated with them. This routine must be followed by either
@ -129,14 +135,10 @@ const GUID * xaccTransGetGUID (Transaction *trans);
Transaction * xaccTransLookup (const GUID *guid);
/* xaccTransGetSlot and xaccTransSetSlot reference the kvp_data
* field of the transaction. kvp_data is used to store arbitrary
* strings, numbers, and structures which aren't "official" members
* of the transaction structure. */
/* Transaction slots are used to store arbitrary strings, numbers, and
* structures which aren't members of the transaction struct. */
kvp_value * xaccTransGetSlot(Transaction * trans, const char * key);
void xaccTransSetSlot(Transaction * trans, const char * key,
const kvp_value * value);
kvp_frame *xaccTransGetSlots(Transaction *trans);
/* The xaccTransSetDateSecs() method will modify the posted date
* of the transaction. (Footnote: this shouldn't matter to a user,
@ -178,7 +180,6 @@ void xaccTransSetDescription (Transaction *trans, const char *desc);
*/
void xaccTransSetMemo (Transaction *trans, const char *memo);
void xaccTransSetAction (Transaction *trans, const char *action);
void xaccTransSetDocref (Transaction *, const char *);
/* The xaccTransAppendSplit() method will append the indicated
* split to the collection of splits in this transaction.
@ -216,12 +217,14 @@ Split * xaccTransGetSplit (Transaction *trans, int i);
*/
const char * xaccTransGetNum (Transaction *trans);
const char * xaccTransGetDescription (Transaction *trans);
const char * xaccTransGetDocref (Transaction *trans);
time_t xaccTransGetDate (Transaction *trans);
#ifndef SWIG /* swig chokes on long long */
long long xaccTransGetDateL (Transaction *trans);
#endif
void xaccTransGetDateTS (Transaction *trans, Timespec *ts);
#define xaccTransGetDatePostedTS xaccTransGetDateTS
void xaccTransGetDateEnteredTS (Transaction *trans, Timespec *ts);
/* The xaccTransGetDateStr() method will return a malloc'ed string
@ -241,10 +244,12 @@ int xaccTransCountSplits (Transaction *trans);
* xaccTransFindCommonCurrency. This method is useful for determining
* whether two accounts can have transactions in common.
*/
gboolean xaccIsCommonCurrency(const char *currency_1, const char *security_1,
const char *currency_2, const char *security_2);
gboolean xaccIsCommonCurrency(const gnc_commodity * currency_1,
const gnc_commodity * security_1,
const gnc_commodity * currency_2,
const gnc_commodity * security_2);
/* The xaccTransFindCommonCurrency () method returns a string value
/* The xaccTransFindCommonCurrency () method returns a gnc_commodity
* indicating a currency denomination that all of the splits in this
* transaction have in common. This routine is useful in dealing
* with currency trading accounts and/or with "stock boxes", where
@ -255,26 +260,26 @@ gboolean xaccIsCommonCurrency(const char *currency_1, const char *security_1,
* If all of the splits share both a common security and a common currency,
* then the string name for the currency is returned.
*/
const char * xaccTransFindCommonCurrency (Transaction *trans);
const gnc_commodity * xaccTransFindCommonCurrency (Transaction *trans);
/* The xaccTransIsCommonCurrency () method compares the input string
/* The xaccTransIsCommonCurrency () method compares the input commodity
* to the currency/security denominations of all splits in the
* transaction, and returns the input string if it is common with
* transaction, and returns the input commodity if it is common with
* all the splits, otherwise, it returns NULL.
*
* Note that this routine is *not* merely a string compare on the
* Note that this routine is *not* merely a compare on the
* value returned by TransFindCommonCurrency(). This is because
* all of the splits in a transaction may share *both* a common
* currency and a common security. If the desired match is the
* security, a simple string match won't reveal this fact.
* security, a simple match won't reveal this fact.
*
* This routine is useful in dealing with currency trading accounts
* and/or with "stock boxes", where transaction have a security in
* common. This routine is useful in dealing with securities of
* differing types as they are moved across accounts.
*/
const char * xaccTransIsCommonCurrency (Transaction *trans,
const char * currency);
const gnc_commodity * xaccTransIsCommonCurrency(Transaction *trans,
const gnc_commodity * curr);
/* The xaccTransIsCommonExclSCurrency () method compares the input
* string to the currency/security denominations of all splits in
@ -286,9 +291,10 @@ const char * xaccTransIsCommonCurrency (Transaction *trans,
* that split is of no relevance when determining whether the new
* entry has a common currency with the other splits.
*/
const char * xaccTransIsCommonExclSCurrency (Transaction *trans,
const char * currency,
Split *excl_split);
const gnc_commodity *
xaccTransIsCommonExclSCurrency (Transaction *trans,
const gnc_commodity * currency,
Split *excl_split);
/* The xaccTransGetImbalance() method returns the total value of the
* transaction. In a pure double-entry system, this imbalance
@ -299,20 +305,20 @@ const char * xaccTransIsCommonExclSCurrency (Transaction *trans,
* in the currency that is returned by the xaccTransFindCommonCurrency()
* method.
*/
double xaccTransGetImbalance (Transaction * trans);
double DxaccTransGetImbalance (Transaction * trans);
gnc_numeric xaccTransGetImbalance (Transaction * trans);
/* ------------- splits --------------- */
Split * xaccMallocSplit (void);
gboolean xaccSplitEqual(const Split *sa, const Split *sb,
gboolean check_guids,
gboolean check_txn_splits);
/* xaccSplitGetSlot and xaccSplitSetSlot reference the kvp_data field
* of the split. kvp_data is used to store arbitrary strings,
* numbers, and structures which aren't "official" members of the
* split structure. */
/* Split slots are used to store arbitrary strings, numbers, and
* structures which aren't members of the transaction struct. */
kvp_value * xaccSplitGetSlot(Split * split, const char * key);
void xaccSplitSetSlot(Split * split, const char * key,
const kvp_value * value);
kvp_frame *xaccSplitGetSlots(Split *trans);
/* The xaccSplitGetGUID() subroutine will return the
* globally unique id associated with that split.
@ -336,9 +342,6 @@ void xaccSplitSetMemo (Split *split, const char *memo);
*/
void xaccSplitSetAction (Split *split, const char *action);
/* docref == hook for additional data, etc */
void xaccSplitSetDocref (Split *, const char *);
/* The Reconcile is a single byte, whose values are typically
* are "N", "C" and "R"
*/
@ -347,7 +350,6 @@ void xaccSplitSetDateReconciledSecs (Split *split, time_t time);
void xaccSplitSetDateReconciledTS (Split *split, Timespec *ts);
void xaccSplitGetDateReconciledTS (Split *split, Timespec *ts);
/*
* The following four functions set the prices and amounts.
* All of the routines always maintain balance: that is,
@ -370,14 +372,21 @@ void xaccSplitGetDateReconciledTS (Split *split, Timespec *ts);
* processing overhead of balancing only once, instead of twice.
*/
void xaccSplitSetSharePriceAndAmount (Split *split, double price,
double amount);
void xaccSplitSetShareAmount (Split *split, double amount);
void xaccSplitSetSharePrice (Split *split, double price);
void xaccSplitSetValue (Split *split, double value);
void xaccSplitSetBaseValue (Split *split, double value,
const char * base_currency);
void DxaccSplitSetSharePriceAndAmount (Split *split, double price,
double amount);
void DxaccSplitSetShareAmount (Split *split, double amount);
void DxaccSplitSetSharePrice (Split *split, double price);
void DxaccSplitSetValue (Split *split, double value);
void DxaccSplitSetBaseValue (Split *split, double value,
const gnc_commodity * base_currency);
void xaccSplitSetSharePriceAndAmount (Split *split, gnc_numeric price,
gnc_numeric amount);
void xaccSplitSetShareAmount (Split *split, gnc_numeric amount);
void xaccSplitSetSharePrice (Split *split, gnc_numeric price);
void xaccSplitSetValue (Split *split, gnc_numeric value);
void xaccSplitSetBaseValue (Split *split, gnc_numeric value,
const gnc_commodity * base_currency);
/* The following four subroutines return the running balance up
* to & including the indicated split.
@ -397,15 +406,23 @@ void xaccSplitSetBaseValue (Split *split, double value,
* of all transactions that have been marked as reconciled.
*/
double xaccSplitGetBalance (Split *split);
double xaccSplitGetClearedBalance (Split *split);
double xaccSplitGetReconciledBalance (Split *split);
double xaccSplitGetShareBalance (Split *split);
double xaccSplitGetShareClearedBalance (Split *split);
double xaccSplitGetShareReconciledBalance (Split *split);
double xaccSplitGetCostBasis (Split *split);
double xaccSplitGetBaseValue (Split *split, const char *base_currency);
double DxaccSplitGetBalance (Split *split);
double DxaccSplitGetClearedBalance (Split *split);
double DxaccSplitGetReconciledBalance (Split *split);
double DxaccSplitGetShareBalance (Split *split);
double DxaccSplitGetShareClearedBalance (Split *split);
double DxaccSplitGetShareReconciledBalance (Split *split);
double DxaccSplitGetBaseValue (Split *split,
const gnc_commodity * base_currency);
gnc_numeric xaccSplitGetBalance (Split *split);
gnc_numeric xaccSplitGetClearedBalance (Split *split);
gnc_numeric xaccSplitGetReconciledBalance (Split *split);
gnc_numeric xaccSplitGetShareBalance (Split *split);
gnc_numeric xaccSplitGetShareClearedBalance (Split *split);
gnc_numeric xaccSplitGetShareReconciledBalance (Split *split);
gnc_numeric xaccSplitGetBaseValue (Split *split,
const gnc_commodity * base_currency);
/* return the parent transaction of the split */
Transaction * xaccSplitGetParent (Split *split);
@ -413,13 +430,16 @@ Transaction * xaccSplitGetParent (Split *split);
/* return the memo, action strings */
const char * xaccSplitGetMemo (Split *split);
const char * xaccSplitGetAction (Split *split);
const char * xaccSplitGetDocref (Split *split);
/* return the value of the reconcile flag */
char xaccSplitGetReconcile (Split *split);
double xaccSplitGetShareAmount (Split * split);
double xaccSplitGetSharePrice (Split * split);
double xaccSplitGetValue (Split * split);
double DxaccSplitGetShareAmount (Split * split);
double DxaccSplitGetSharePrice (Split * split);
double DxaccSplitGetValue (Split * split);
gnc_numeric xaccSplitGetShareAmount (Split * split);
gnc_numeric xaccSplitGetSharePrice (Split * split);
gnc_numeric xaccSplitGetValue (Split * split);
Account * xaccSplitGetAccount (Split *split);
@ -429,7 +449,7 @@ Account * xaccSplitGetAccount (Split *split);
* The xaccTransOrder(ta,tb) method is useful for sorting.
* return a negative value if transaction ta is dated earlier than tb,
* return a positive value if transaction ta is dated later than tb,
* then compares num, description and docref values, using the strcmp()
* then compares num and description values, using the strcmp()
* c-library routine, returning what strcmp would return.
* Finally, it returns zero if all of the above match.
* Note that it does *NOT* compare its member splits.
@ -442,7 +462,6 @@ Account * xaccSplitGetAccount (Split *split);
* then compares memo and action using the strcmp()
* c-library routine, returning what strcmp would return.
* Then it compares the reconciled flags, then the reconciled dates,
* Then it strcmps() the docref fields.
* Finally, it returns zero if all of the above match.
* Note that it does *NOT* compare its parent transaction.
*
@ -453,9 +472,9 @@ Account * xaccSplitGetAccount (Split *split);
*
*/
int xaccTransOrder (Transaction **ta, Transaction **tb);
int xaccSplitOrder (Split **sa, Split **sb);
int xaccSplitDateOrder (Split **sa, Split **sb);
int xaccTransOrder (Transaction *ta, Transaction *tb);
int xaccSplitOrder (Split *sa, Split *sb);
int xaccSplitDateOrder (Split *sa, Split *sb);
/********************************************************************\
* Miscellaneous utility routines.

View File

@ -50,6 +50,7 @@
#include "config.h"
#include "kvp_frame.h"
#include "gnc-numeric.h"
#include "Transaction.h" /* for typedefs */
#include "GNCId.h"
@ -94,14 +95,6 @@ struct _split
*/
char * action; /* Buy, Sell, Div, etc. */
/* The docref field is a hook for arbitrary additional user-assigned
* data, such as invoice numbers, clearing/posting reference numbers,
* supporting document references, etc. This additional data should
* be encoded in a machine-readable format, e.g. a mime-type encapsulated
* form, which any key-value pairs being URL-encoded.
*/
char * docref;
/* kvp_data is a key-value pair database for storing simple
* "extra" information in splits, transactions, and accounts.
* it's NULL until accessed. */
@ -112,8 +105,12 @@ struct _split
char reconciled;
Timespec date_reconciled; /* date split was reconciled */
double damount; /* num-shares; if > 0.0, deposit, else paymt */
double share_price; /* the share price, ==1.0 for bank account */
/* value is the amount of the account's currency involved,
* damount is the amount of the account's security. For
* bank-type accounts, currency == security and
* value == damount. */
gnc_numeric value;
gnc_numeric damount;
/* -------------------------------------------------------------- */
/* Below follow some 'temporary' fields */
@ -122,15 +119,13 @@ struct _split
* all the splits in the account, up to and including this split.
* These balances apply to a sorting order by date posted
* (not by date entered). */
double balance;
double cleared_balance;
double reconciled_balance;
gnc_numeric balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
double share_balance;
double share_cleared_balance;
double share_reconciled_balance;
double cost_basis;
gnc_numeric share_balance;
gnc_numeric share_cleared_balance;
gnc_numeric share_reconciled_balance;
};
@ -155,14 +150,6 @@ struct _transaction
*/
char * description;
/* The docref field is a hook for arbitrary additional user-assigned
* data, such as invoice numbers, clearing/posting reference numbers,
* supporting document references, etc. This additional data should
* be encoded in a machine-readable format, e.g. a mime-type encapsulated
* form, which any key-value pairs being URL-encoded.
*/
char * docref;
/* kvp_data is a key-value pair database for storing simple
* "extra" information in splits, transactions, and accounts.
* it's NULL until accessed. */
@ -189,7 +176,6 @@ struct _transaction
Transaction *orig;
};
/* Set the transaction's GUID. This should only be done when reading
* a transaction from a datafile, or some other external source. Never
* call this on an existing transaction! */
@ -253,4 +239,9 @@ void xaccTransRemoveSplit (Transaction*, Split *);
void xaccSplitRebalance (Split *);
/* FIXME: this is probably wrong, but it'll have to wait until Bill
returns. It's *ONLY* for file IO. Don't use these elsewhere. */
void xaccSplitSetValueDirectly(Split *s, gnc_numeric n);
void xaccSplitSetQuantityDirectly(Split *s, gnc_numeric n);
#endif /* __XACC_TRANSACTION_P_H__ */

View File

@ -47,6 +47,12 @@ static short module = MOD_ENGINE;
/********************************************************************\
\********************************************************************/
gboolean
timespec_equal(const Timespec *ta, const Timespec *tb) {
if(ta->tv_sec != tb->tv_sec) return FALSE;
if(ta->tv_nsec != tb->tv_nsec) return FALSE;
return TRUE;
}
/**
* setDateFormat

View File

@ -32,6 +32,7 @@
#define __XACC_DATE_H__
#include "config.h"
#include "glib.h"
/** Constants *******************************************************/
@ -75,6 +76,9 @@ typedef struct timespec64 Timespec;
/** Prototypes ******************************************************/
gboolean timespec_equal(const Timespec *ta, const Timespec *tb);
void setDateFormat(DateFormat df);
/**

472
src/engine/gnc-commodity.c Normal file
View File

@ -0,0 +1,472 @@
/********************************************************************
* gnc_commodity.c -- representing tradable commodities *
* Copyright (C) 2000 Bill Gribble *
* *
* 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 <limits.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <glib.h>
#include "gnc-commodity.h"
#include "util.h"
/* parts per unit is nominal, i.e. number of 'partname' units in
* a 'unitname' unit. fraction is transactional, i.e. how many
* of the smallest-transactional-units of the currency are there
* in a 'unitname' unit. */
struct _gnc_commodity {
char * fullname;
char * namespace;
char * mnemonic;
char * printname;
char * exchange_code; /* CUSIP or other identifying code */
int fraction;
};
struct _gnc_commodity_namespace {
GHashTable * table;
};
struct _gnc_commodity_table {
GHashTable * table;
};
typedef struct _gnc_commodity_namespace gnc_commodity_namespace;
/********************************************************************
* gnc_commodity_new
********************************************************************/
gnc_commodity *
gnc_commodity_new(const char * fullname,
const char * namespace, const char * mnemonic,
const char * exchange_code,
int fraction) {
gnc_commodity * retval = g_new0(gnc_commodity, 1);
retval->fullname = g_strdup(fullname);
retval->namespace = g_strdup(namespace);
retval->mnemonic = g_strdup(mnemonic);
retval->exchange_code = g_strdup(exchange_code);
retval->fraction = fraction;
retval->printname = g_strdup_printf("%s:%s (%s)",
retval->namespace,
retval->mnemonic,
retval->fullname);
return retval;
}
/********************************************************************
* gnc_commodity_destroy
********************************************************************/
void
gnc_commodity_destroy(gnc_commodity * cm) {
if(!cm) return;
g_free(cm->fullname);
g_free(cm->printname);
g_free(cm->namespace);
g_free(cm->mnemonic);
g_free(cm);
}
/********************************************************************
* gnc_commodity_get_mnemonic
********************************************************************/
const char *
gnc_commodity_get_mnemonic(const gnc_commodity * cm) {
if(!cm) return NULL;
return cm->mnemonic;
}
/********************************************************************
* gnc_commodity_get_printname
********************************************************************/
const char *
gnc_commodity_get_printname(const gnc_commodity * cm) {
if(!cm) return NULL;
return cm->printname;
}
/********************************************************************
* gnc_commodity_get_namespace
********************************************************************/
const char *
gnc_commodity_get_namespace(const gnc_commodity * cm) {
if(!cm) return NULL;
return cm->namespace;
}
/********************************************************************
* gnc_commodity_get_fullname
********************************************************************/
const char *
gnc_commodity_get_fullname(const gnc_commodity * cm) {
if(!cm) return NULL;
return cm->fullname;
}
/********************************************************************
* gnc_commodity_get_exchange_code
********************************************************************/
const char *
gnc_commodity_get_exchange_code(const gnc_commodity * cm) {
if(!cm) return NULL;
return cm->exchange_code;
}
/********************************************************************
* gnc_commodity_get_fraction
********************************************************************/
int
gnc_commodity_get_fraction(const gnc_commodity * cm) {
if(!cm) return 0;
return cm->fraction;
}
/********************************************************************
* gnc_commodity_set_mnemonic
********************************************************************/
void
gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic) {
if(!cm) return;
g_free(cm->mnemonic);
cm->mnemonic = g_strdup(mnemonic);
g_free(cm->printname);
cm->printname = g_strdup_printf("%s:%s (%s)",
cm->namespace, cm->mnemonic, cm->fullname);
}
/********************************************************************
* gnc_commodity_set_namespace
********************************************************************/
void
gnc_commodity_set_namespace(gnc_commodity * cm, const char * namespace) {
if(!cm) return;
g_free(cm->namespace);
cm->namespace = g_strdup(namespace);
}
/********************************************************************
* gnc_commodity_set_fullname
********************************************************************/
void
gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname) {
if(!cm) return;
g_free(cm->fullname);
cm->fullname = g_strdup(fullname);
g_free(cm->printname);
cm->printname = g_strdup_printf("%s:%s (%s)",
cm->namespace, cm->mnemonic, cm->fullname);
}
/********************************************************************
* gnc_commodity_set_exchange_code
********************************************************************/
void
gnc_commodity_set_exchange_code(gnc_commodity * cm,
const char * exchange_code) {
if(!cm) return;
cm->exchange_code = g_strdup(exchange_code);
}
/********************************************************************
* gnc_commodity_set_fraction
********************************************************************/
void
gnc_commodity_set_fraction(gnc_commodity * cm, int fraction) {
if(!cm) return;
cm->fraction = fraction;
}
/********************************************************************
* gnc_commodity_equiv
* are two commodities the same?
********************************************************************/
gboolean
gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b) {
/* fprintf(stderr, "CmpCmod %p ?= %p\n", a, b); */
if(a == b) return TRUE;
if(!a || !b) return FALSE;
/* fprintf(stderr, "CmpCmod %s:%s ?= %s:%s\n",
a->namespace, a->mnemonic,
b->namespace, b->mnemonic); */
if(safe_strcmp(a->namespace, b->namespace) != 0) return FALSE;
if(safe_strcmp(a->mnemonic, b->mnemonic) != 0) return FALSE;
return TRUE;
}
/********************************************************************
* gnc_commodity_table_new
* make a new commodity table
********************************************************************/
gnc_commodity_table *
gnc_commodity_table_new(void) {
gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
retval->table = g_hash_table_new(&g_str_hash, &g_str_equal);
return retval;
}
/********************************************************************
* gnc_commodity_table_lookup
* locate a commodity by namespace and mnemonic.
********************************************************************/
gnc_commodity *
gnc_commodity_table_lookup(const gnc_commodity_table * table,
const char * namespace, const char * mnemonic) {
gnc_commodity_namespace * nsp = NULL;
nsp = g_hash_table_lookup(table->table, (gpointer)namespace);
if(nsp) {
return g_hash_table_lookup(nsp->table, (gpointer)mnemonic);
}
else {
return NULL;
}
}
/********************************************************************
* gnc_commodity_table_find_full
* locate a commodity by namespace and printable name
********************************************************************/
gnc_commodity *
gnc_commodity_table_find_full(const gnc_commodity_table * table,
const char * namespace,
const char * fullname) {
gnc_commodity * retval=NULL;
GList * all;
GList * iterator;
all = gnc_commodity_table_get_commodities(table, namespace);
if(fullname && fullname[0]) {
for(iterator = all; iterator; iterator=iterator->next) {
if(!strcmp(fullname,
gnc_commodity_get_printname(iterator->data))) {
retval = iterator->data;
break;
}
}
return retval;
}
else {
return NULL;
}
}
/********************************************************************
* gnc_commodity_table_insert
* add a commodity to the table.
********************************************************************/
void
gnc_commodity_table_insert(gnc_commodity_table * table,
const gnc_commodity * comm) {
gnc_commodity_namespace * nsp = NULL;
nsp = g_hash_table_lookup(table->table, (gpointer)(comm->namespace));
if(!nsp) {
nsp = g_new0(gnc_commodity_namespace, 1);
nsp->table = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(table->table, (gpointer)(comm->namespace),
(gpointer)nsp);
}
return g_hash_table_insert(nsp->table,
(gpointer)comm->mnemonic,
(gpointer)comm);
}
/********************************************************************
* gnc_commodity_table_remove
* remove a commodity from the table (just unmaps it)
********************************************************************/
void
gnc_commodity_table_remove(gnc_commodity_table * table,
const gnc_commodity * comm) {
gnc_commodity_namespace * nsp = NULL;
nsp = g_hash_table_lookup(table->table, (gpointer)(comm->namespace));
if(nsp) {
g_hash_table_remove(nsp->table, (gpointer)comm->mnemonic);
}
}
/********************************************************************
* gnc_commodity_table_has_namespace
* see if any commodities in the namespace exist
********************************************************************/
int
gnc_commodity_table_has_namespace(const gnc_commodity_table * table,
const char * namespace) {
gnc_commodity_namespace * nsp = NULL;
if(!table || !namespace) { return 0; }
nsp = g_hash_table_lookup(table->table, (gpointer)namespace);
if(nsp) {
return 1;
}
else {
return 0;
}
}
static void
hash_keys_helper(gpointer key, gpointer value, gpointer data) {
GList ** l = data;
*l = g_list_append(*l, key);
}
static GList *
g_hash_table_keys(GHashTable * table) {
GList * l = NULL;
g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
return l;
}
static void
hash_values_helper(gpointer key, gpointer value, gpointer data) {
GList ** l = data;
*l = g_list_append(*l, value);
}
static GList *
g_hash_table_values(GHashTable * table) {
GList * l = NULL;
g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
return l;
}
/********************************************************************
* gnc_commodity_table_get_namespaces
* see if any commodities in the namespace exist
********************************************************************/
GList *
gnc_commodity_table_get_namespaces(const gnc_commodity_table * table) {
return g_hash_table_keys(table->table);
}
/********************************************************************
* gnc_commodity_table_get_commodities
* list commodities in a give namespace
********************************************************************/
GList *
gnc_commodity_table_get_commodities(const gnc_commodity_table * table,
const char * namespace) {
gnc_commodity_namespace * ns = NULL;
if(table) {
ns = g_hash_table_lookup(table->table, (gpointer)namespace);
}
if(ns) {
return g_hash_table_values(ns->table);
}
else {
return NULL;
}
}
/********************************************************************
* gnc_commodity_table_add_namespace
* add an empty namespace if it does not exist
********************************************************************/
void
gnc_commodity_table_add_namespace(gnc_commodity_table * table,
const char * namespace) {
gnc_commodity_namespace * ns = NULL;
if(table) {
ns = g_hash_table_lookup(table->table, (gpointer)namespace);
}
if(!ns) {
ns = g_new0(gnc_commodity_namespace, 1);
ns->table = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(table->table, (gpointer)(namespace),
(gpointer)ns);
}
}
/********************************************************************
* gnc_commodity_table_delete_namespace
* delete a namespace
********************************************************************/
void
gnc_commodity_table_delete_namespace(gnc_commodity_table * table,
const char * namespace) {
gnc_commodity_namespace * ns = NULL;
if(table) {
ns = g_hash_table_lookup(table->table, (gpointer)namespace);
}
if(ns) {
g_hash_table_remove(table->table, namespace);
}
}

View File

@ -0,0 +1,93 @@
/********************************************************************
* gnc_commodity.h -- representing tradable commodities *
* Copyright (C) 2000 Bill Gribble *
* *
* 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_COMMODITY_H__
#define __GNC_COMMODITY_H__
#include <glib.h>
typedef struct _gnc_commodity gnc_commodity;
typedef struct _gnc_commodity_table gnc_commodity_table;
#define GNC_COMMODITY_NS_LEGACY "GNC_LEGACY_CURRENCIES"
#define GNC_COMMODITY_NS_ISO "ISO4217"
#define GNC_COMMODITY_NS_NASDAQ "NASDAQ"
#define GNC_COMMODITY_NS_NYSE "NYSE"
#define GNC_COMMODITY_NS_EUREX "EUREX"
#define GNC_COMMODITY_NS_MUTUAL "FUND"
#define GNC_COMMODITY_NS_AMEX "AMEX"
/* gnc_commodity functions */
gnc_commodity * gnc_commodity_new(const char * fullname,
const char * namespace,
const char * mnemonic,
const char * exchange_code,
int fraction);
void gnc_commodity_destroy(gnc_commodity * cm);
const char * gnc_commodity_get_mnemonic(const gnc_commodity * cm);
const char * gnc_commodity_get_namespace(const gnc_commodity * cm);
const char * gnc_commodity_get_fullname(const gnc_commodity * cm);
const char * gnc_commodity_get_printname(const gnc_commodity * cm);
const char * gnc_commodity_get_exchange_code(const gnc_commodity * cm);
int gnc_commodity_get_fraction(const gnc_commodity * cm);
void gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic);
void gnc_commodity_set_namespace(gnc_commodity * cm, const char * namespace);
void gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname);
void gnc_commodity_set_exchange_code(gnc_commodity * cm,
const char * exchange_code);
void gnc_commodity_set_fraction(gnc_commodity * cm, int smallest_fraction);
gboolean gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b);
/* gnc_commodity_table functions : operate on a database of commodity
* info */
gnc_commodity_table * gnc_commodity_table_new(void);
void gnc_commodity_table_destroy(gnc_commodity_table * table);
gnc_commodity * gnc_commodity_table_lookup(const gnc_commodity_table * table,
const char * namespace,
const char * mnemonic);
gnc_commodity * gnc_commodity_table_find_full(const gnc_commodity_table * t,
const char * namespace,
const char * fullname);
void gnc_commodity_table_insert(gnc_commodity_table * table,
const gnc_commodity * comm);
void gnc_commodity_table_remove(gnc_commodity_table * table,
const gnc_commodity * comm);
int gnc_commodity_table_has_namespace(const gnc_commodity_table * t,
const char * namespace);
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table * t);
GList * gnc_commodity_table_get_commodities(const gnc_commodity_table * t,
const char * namespace);
void gnc_commodity_table_add_namespace(gnc_commodity_table * table,
const char * namespace);
void gnc_commodity_table_delete_namespace(gnc_commodity_table * t,
const char * namespace);
#endif

79
src/engine/gnc-engine.c Normal file
View File

@ -0,0 +1,79 @@
/********************************************************************
* gnc-engine.c -- top-level initialization for Gnucash Engine *
* Copyright 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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 <glib.h>
#include <assert.h>
#include "gnc-engine.h"
static GList * engine_init_hooks = NULL;
static gnc_commodity_table * known_commodities = NULL;
static int engine_is_initialized = 0;
/********************************************************************
* gnc_engine_init
* initialize backend, load any necessary databases, etc.
********************************************************************/
void
gnc_engine_init(int argc, char ** argv) {
gnc_engine_init_hook_t hook;
GList * cur;
engine_is_initialized = 1;
/* initialize the commodity table (it starts empty) */
known_commodities = gnc_commodity_table_new();
/* call any engine hooks */
for(cur = engine_init_hooks; cur; cur = cur->next) {
hook = (gnc_engine_init_hook_t)cur->data;
if(hook) {
(*hook)(argc, argv);
}
}
}
/********************************************************************
* gnc_engine_add_init_hook
* add a startup hook
********************************************************************/
void
gnc_engine_add_init_hook(gnc_engine_init_hook_t h) {
engine_init_hooks = g_list_append(engine_init_hooks, (gpointer)h);
}
/********************************************************************
* gnc_engine_commodities()
* get the global gnc_engine commodity table
********************************************************************/
gnc_commodity_table *
gnc_engine_commodities(void) {
assert(engine_is_initialized);
return known_commodities;
}

45
src/engine/gnc-engine.h Normal file
View File

@ -0,0 +1,45 @@
/********************************************************************
* gnc-engine.h -- top-level include file for Gnucash Engine *
* Copyright 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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_ENGINE_H__
#define __GNC_ENGINE_H__
#include "gnc-commodity.h"
typedef void (* gnc_engine_init_hook_t)(int, char **);
/** PROTOTYPES ******************************************************/
/* gnc_engine_init MUST be called before gnc engine functions can
* be used. */
void gnc_engine_init(int argc, char ** argv);
/* pass a function pointer to gnc_engine_add_init_hook and
* it will be called during the evaluation of gnc_engine_init */
void gnc_engine_add_init_hook(gnc_engine_init_hook_t hook);
/* this is a global table of known commodity types. */
gnc_commodity_table * gnc_engine_commodities(void);
#endif

1122
src/engine/gnc-numeric.c Normal file

File diff suppressed because it is too large Load Diff

155
src/engine/gnc-numeric.h Normal file
View File

@ -0,0 +1,155 @@
/********************************************************************
* gnc-numeric.h -- an exact-number library for gnucash. *
* Copyright (C) 2000 Bill Gribble *
* *
* 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_NUMERIC_H__
#define __GNC_NUMERIC_H__
#include <glib.h>
struct _gnc_numeric {
gint64 num;
gint64 denom;
};
typedef struct _gnc_numeric gnc_numeric;
/* bitmasks for HOW flags */
#define GNC_NUMERIC_RND_MASK 0x0000000f
#define GNC_NUMERIC_DENOM_MASK 0x000000f0
/* rounding/truncation modes for operations */
enum {
GNC_RND_FLOOR = 0x01,
GNC_RND_CEIL = 0x02,
GNC_RND_TRUNC = 0x03,
GNC_RND_PROMOTE = 0x04,
GNC_RND_ROUND_HALF_DOWN = 0x05,
GNC_RND_ROUND_HALF_UP = 0x06,
GNC_RND_ROUND = 0x07,
GNC_RND_NEVER = 0x08
};
/* auto-denominator types */
enum {
GNC_DENOM_EXACT = 0x10,
GNC_DENOM_REDUCE = 0x20,
GNC_DENOM_LCD = 0x30,
GNC_DENOM_FIXED = 0x40
};
/* errors */
enum {
GNC_ERROR_OK = 0,
GNC_ERROR_ARG = -1,
GNC_ERROR_OVERFLOW = -2,
GNC_ERROR_DENOM_DIFF = -3,
GNC_ERROR_REMAINDER = -4
};
#define GNC_DENOM_AUTO 0
#define GNC_DENOM_RECIPROCAL( a ) (- ( a ))
/* make a gnc_numeric from numerator and denominator */
gnc_numeric gnc_numeric_create(gint64 num, gint64 denom);
/* create a zero-value gnc_numeric */
gnc_numeric gnc_numeric_zero(void);
/* make a special error-signalling gnc_numeric */
gnc_numeric gnc_numeric_error(int error_code);
/* check for error signal in value */
int gnc_numeric_check(gnc_numeric a);
/* get parts */
gint64 gnc_numeric_num(gnc_numeric a);
gint64 gnc_numeric_denom(gnc_numeric a);
/* tests */
int gnc_numeric_zero_p(gnc_numeric a); /* 1 if 0, 0 else */
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b);
int gnc_numeric_negative_p(gnc_numeric a);
int gnc_numeric_positive_p(gnc_numeric a);
/* equivalence predicates :
* eq : a and b are exactly the same (same numerator and denominator)
* equal : a and b represent exactly the same number (ratio of numerator
* to denominator is exactly equal)
* same : after both are converted to DENOM using method HOW, a and b
* are equal().
*/
int gnc_numeric_eq(gnc_numeric a, gnc_numeric b);
int gnc_numeric_equal(gnc_numeric a, gnc_numeric b);
int gnc_numeric_same(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
/* arithmetic operations */
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how);
gnc_numeric gnc_numeric_neg(gnc_numeric a);
/* some shortcuts for common operations */
gnc_numeric gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b);
gnc_numeric gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b);
/* arithmetic functions with exact error returns */
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b,
gint64 denom, gint how,
gnc_numeric * error);
/* change the denominator of a gnc_numeric value */
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom,
gint how);
gnc_numeric gnc_numeric_convert_with_error(gnc_numeric in, gint64 denom,
gint how,
gnc_numeric * error);
/* reduce by GCF elimination */
gnc_numeric gnc_numeric_reduce(gnc_numeric in);
/* convert to and from floating-point values */
gnc_numeric double_to_gnc_numeric(double in, gint64 denom,
gint how);
double gnc_numeric_to_double(gnc_numeric in);
gchar *gnc_numeric_to_string(gnc_numeric n);
const gchar *string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
#endif

View File

@ -430,6 +430,8 @@ guid_to_string(const GUID * guid)
char *string = malloc(GUID_ENCODING_LENGTH+1);
if (!string) return NULL;
if(!guid) return(NULL);
encode_md5_data(guid->data, string);
string[GUID_ENCODING_LENGTH] = '\0';
@ -451,3 +453,51 @@ guid_equal(const GUID *guid_1, const GUID *guid_2)
else
return FALSE;
}
gint
guid_compare(const GUID *guid_1, const GUID *guid_2) {
if(guid_1 == guid_2) return 0;
/* nothing is always less than something */
if(!guid_1 && guid_2) return -1;
if(guid_1 && !guid_2) return 1;
return(memcmp(guid_1, guid_2, sizeof(GUID)));
}
guint
guid_hash_to_guint(gconstpointer ptr)
{
GUID *guid = (GUID *) ptr;
if(!guid) {
fprintf(stderr, "guid_g_hash_table_hash: received NULL guid pointer.");
return(0);
}
if (sizeof(guint) <= sizeof(guid->data)) {
return(*((guint *) guid->data));
} else {
guint hash = 0;
int i, j;
for (i = 0, j = 0; i < sizeof(guint); i++, j++) {
if (j == 16) j = 0;
hash <<= 4;
hash |= guid->data[j];
}
return(hash);
}
}
static gint
guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
{
return((gint) guid_equal((GUID *) guid_a, (GUID *) guid_b));
}
GHashTable *
guid_hash_table_new() {
return(g_hash_table_new(guid_hash_to_guint, guid_g_hash_table_equal));
}

View File

@ -21,8 +21,8 @@
* *
\********************************************************************/
#ifndef __GUID__
#define __GUID__
#ifndef __GUID_H__
#define __GUID_H__
#ifdef HAVE_CONFIG_H
# include <config.h>
@ -91,5 +91,11 @@ gboolean string_to_guid(const char * string, GUID * guid);
/* Given two GUIDs, return TRUE if they are non-NULL and equal.
* Return FALSE, otherwise. */
gboolean guid_equal(const GUID *guid_1, const GUID *guid_2);
gint guid_compare(const GUID *g1, const GUID *g2);
/* Given a GUID *, hash it to a guint */
guint guid_hash_to_guint(gconstpointer ptr);
GHashTable *guid_hash_table_new();
#endif

43
src/engine/guid_private.h Normal file
View File

@ -0,0 +1,43 @@
/********************************************************************\
* guid_private.h -- globally unique ID User API (private bits) *
* Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu> *
* *
* 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 __GUID_PRIVATE__
#define __GUID_PRIVATE__
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <glib.h>
/* This file defines an API for using globally unique identifiers. */
/* The type used to store guids */
typedef union _GUID
{
unsigned char data[16];
int __align_me; /* this just ensures that GUIDs are 32-bit
* aligned on systems that need them to be. */
} GUID;

1928
src/engine/io-gncbin-r.c Normal file

File diff suppressed because it is too large Load Diff

76
src/engine/io-gncbin.h Normal file
View File

@ -0,0 +1,76 @@
/********************************************************************\
* io-gncbin.h -- read from and writing to a datafile for gnucash *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1998, 1999 Linas Vepstas *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* 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 *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#ifndef __IO_GNCBIN_H__
#define __IO_GNCBIN_H__
#include "Group.h"
#include "FileIO.h"
/** PROTOTYPES ******************************************************/
/*
* The xaccReadAccountGroupFD() and xaccWriteAccountGroupFD()
* routines read and write the GnuCash "xacc" byte stream (file)
* format. This is a binary format that exactly represents all of the
* data that can appear in the AccountGroup structure as a sequence of
* bytes. The Read and Write routines are exact inverses of each other:
* that is, there is no loss of data involved in converting an
* AccountGroup into a byte stream and back again. These routines
* can be thought of as implementing a kind of "object persistance"
* for the AccountGroup object. Note that these routines can also
* be used to provide inter-process communication using either pipes or
* sockets. That is, by writing into a socket or pipe with the
* xaccWriteAccountGroupFD() routine, and reading from it at the other
* end with the xaccReadAccountGroupFD() routine, an exact duplicate of
* the AccountGroup can be created in a different process.
*
* NOTE: These routines should not be used directly for file IO.
* They are not inherently safe against file-locking errors.
* For direct file IO, the Session object should be used.
*
* The xaccReadOldBinAccountGroupFile() method will read the "xacc"
* format byte stream from the indicated file, and build and return
* the corresponding AccountGroup structure.
*
* If a read error occurred during reading, the returned value
* may or may not be null. Use the xaccGetOldBinFileIOError() routine
* to check for read errors.
*
* The xaccGetOldBinFileIOError() method will return an error code for
* any error detected that occured during reading or writing. It
* will reset the error code after being called. The current
* implementation can be thought of as a "stack of depth one", and
* this routine as a "pop". Future implementations may have a
* deeper stack.
* */
AccountGroup *xaccReadGncBinAccountGroupFile (const char *filename);
GNCFileIOError xaccGetGncBinFileIOError (void);
#endif /* __IO_GNCBIN_H__ */

4720
src/engine/io-gncxml-r.c Normal file

File diff suppressed because it is too large Load Diff

772
src/engine/io-gncxml-w.c Normal file
View File

@ -0,0 +1,772 @@
#define _GNU_SOURCE
#include <glib.h>
#include <stdio.h>
#include <tree.h>
#include <parser.h>
#include <xmlmemory.h>
#include <parserInternals.h>
#include "Account.h"
#include "date.h"
#include "DateUtils.h"
#include "Group.h"
#include "messages.h"
#include "Transaction.h"
#include "TransLog.h"
#include "util.h"
#include "gnc-engine.h"
#include "io-gncxml.h"
#include "AccountP.h" /* just for kvp_data */
#include "TransactionP.h" /* just for kvp_data */
/* Hack to get going... */
#include "FileIOP.h"
#include <guile/gh.h>
static gboolean
xml_add_str(xmlNodePtr p, const char *tag, const char *str,
gboolean include_if_empty) {
xmlNodePtr child;
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!str && !include_if_empty) return(TRUE);
if((strlen(str) == 0) && !include_if_empty) return(TRUE);
child = xmlNewChild(p, NULL, tag, str);
if(!child) return(FALSE);
return(TRUE);
}
static gboolean
xml_add_character(xmlNodePtr p, const char *tag, const char c) {
char str[2];
str[0] = c;
str[1] = '\0';
return(xml_add_str(p, tag, str, FALSE));
}
static gboolean
xml_add_gint64(xmlNodePtr p, const char *tag, const gint64 value) {
xmlNodePtr val_xml;
const gchar *numstr;
if(!p) return(FALSE);
if(!tag) return(FALSE);
numstr = g_strdup_printf("%lld", value);
if(!numstr) return(FALSE);
val_xml = xmlNewChild(p, NULL, tag, numstr);
g_free((char *) numstr);
if(!val_xml) return(FALSE);
return(TRUE);
}
static gboolean
xml_add_double(xmlNodePtr p, const char *tag, const double value) {
/* FIXME: NOT THREAD SAFE - USES STATIC DATA */
if(!p) return(FALSE);
if(!tag) return(FALSE);
{
static SCM number_to_string;
static gboolean ready = FALSE;
const char *numstr;
if(!ready) {
number_to_string = gh_eval_str("number->string");
scm_protect_object(number_to_string);
ready = TRUE;
}
numstr = gh_scm2newstr(gh_call1(number_to_string, gh_double2scm(value)),
NULL);
if(!numstr) {
return(FALSE);
} else {
xmlNodePtr child = xmlNewChild(p, NULL, tag, numstr);
free((void *) numstr);
if(!child) return(FALSE);
}
}
return(TRUE);
}
static gboolean
xml_add_gnc_numeric(xmlNodePtr p, const char *tag, const gnc_numeric n) {
char *numstr;
xmlNodePtr child;
if(!p) return(FALSE);
if(!tag) return(FALSE);
/* fprintf(stderr, "WRITE GNUM S: %lld/%lld -> ", n.num, n.denom); */
numstr = gnc_numeric_to_string(n);
if(!numstr) return(FALSE);
/* fprintf(stderr, "%s\n", numstr); */
child = xmlNewChild(p, NULL, tag, numstr);
g_free(numstr); numstr = FALSE;
if(!child) return(FALSE);
return(TRUE);
}
static gboolean
xml_add_guid(xmlNodePtr p, const char *tag, const GUID *guid) {
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!guid) return(FALSE);
{
const char *guidstr;
xmlNodePtr child;
if(!guid) {
guidstr = NULL;
} else {
guidstr = guid_to_string(guid);
if(!guidstr) return(FALSE);
}
child = xmlNewChild(p, NULL, tag, guidstr);
if(!child) return(FALSE);
if(guidstr) free((void *) guidstr);
}
return(TRUE);
}
static gboolean
xml_add_editable_timespec(xmlNodePtr p,
const char *tag,
const Timespec *ts,
gboolean include_if_zero) {
xmlNodePtr timespec_xml;
xmlNodePtr secs_xml;
size_t num_written;
struct tm parsed_time;
time_t tmp_timet;
char secs_str[512]; /* This should be way bigger than we need.
Still, it's bogus, we ought to have
astrftime... */
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!ts) return(FALSE);
if(!include_if_zero && (ts->tv_sec == 0) && (ts->tv_nsec == 0)) return TRUE;
tmp_timet = ts->tv_sec;
if(!localtime_r(&tmp_timet, &parsed_time)) return(FALSE);
num_written = strftime(secs_str, sizeof(secs_str),
"%Y-%m-%d %H:%M:%S %z",
&parsed_time);
if(num_written == 0) return(FALSE);
timespec_xml= xmlNewChild(p, NULL, tag, NULL);
if(!timespec_xml) return(FALSE);
secs_xml = xmlNewChild(timespec_xml, NULL, "s", secs_str);
if(!secs_xml) return(FALSE);
if(ts->tv_nsec) {
xmlNodePtr nsec_xml;
gchar *nsec_str = g_strdup_printf("%ld", ts->tv_nsec);
if(!nsec_str) return(FALSE);
nsec_xml = xmlNewChild(timespec_xml, NULL, "ns", nsec_str);
if(!nsec_xml) return(FALSE);
g_free(nsec_str);
}
return(TRUE);
}
static gboolean
xml_add_commodity_ref(xmlNodePtr p, const char *tag, const gnc_commodity *c) {
xmlNodePtr c_xml = NULL;
gboolean ok = FALSE;
if(p && tag) {
if(!c) {
ok = TRUE;
} else {
c_xml= xmlNewChild(p, NULL, tag, NULL);
if(c_xml) {
const gchar *namestr = gnc_commodity_get_namespace(c);
if(namestr) {
xmlNodePtr namespace_xml = xmlNewChild(c_xml, NULL, "space", namestr);
if(namespace_xml) {
const gchar *idstr = gnc_commodity_get_mnemonic(c);
xmlNodePtr id_xml = xmlNewChild(c_xml, NULL, "id", idstr);
if(id_xml) ok = TRUE;
}
}
}
}
}
if(!ok && c_xml) xmlFreeNode(c_xml);
return(TRUE);
}
static gboolean
xml_add_commodity_restorer(xmlNodePtr p, gnc_commodity *c) {
xmlNodePtr comm_xml;
xmlNodePtr rst_xml;
if(!p) return(FALSE);
if(!c) return(FALSE);
comm_xml = xmlNewChild(p, NULL, "commodity", NULL);
if(!comm_xml) return(FALSE);
rst_xml = xmlNewChild(comm_xml, NULL, "restore", NULL);
if(!rst_xml) {
xmlFreeNode(comm_xml);
return(FALSE);
}
if(!xml_add_str(rst_xml, "space", gnc_commodity_get_namespace(c), FALSE)) {
xmlFreeNode(comm_xml);
return(FALSE);
}
if(!xml_add_str(rst_xml, "id", gnc_commodity_get_mnemonic(c), FALSE)) {
xmlFreeNode(comm_xml);
return(FALSE);
}
if(!xml_add_str(rst_xml, "name", gnc_commodity_get_fullname(c), FALSE)) {
xmlFreeNode(comm_xml);
return(FALSE);
}
if(!xml_add_str(rst_xml, "xcode", gnc_commodity_get_exchange_code(c), FALSE)) {
xmlFreeNode(comm_xml);
return(FALSE);
}
if(!xml_add_gint64(rst_xml, "fraction", gnc_commodity_get_fraction(c))) {
xmlFreeNode(comm_xml);
return(FALSE);
}
return(TRUE);
}
static gboolean
xml_add_commodity_restorers(xmlNodePtr p) {
GList *lp;
gnc_commodity_table *commodities;
if(!p) return(FALSE);
commodities = gnc_engine_commodities();
if(!commodities) return(FALSE);
for(lp = gnc_commodity_table_get_namespaces(commodities); lp; lp = lp->next) {
gchar *space;
if(!lp->data) return(FALSE);
if(!lp->data) return(FALSE);
space = (gchar *) lp->data;
if(strcmp(GNC_COMMODITY_NS_ISO, space) != 0) {
GList *comms = gnc_commodity_table_get_commodities(commodities, space);
GList *lp2;
for(lp2 = comms; lp2; lp2 = lp2->next) {
gnc_commodity *com = (gnc_commodity *) lp2->data;
if(!xml_add_commodity_restorer(p, com)) return(FALSE);
}
}
}
return(TRUE);
}
static gboolean
xml_add_binary(xmlNodePtr p,
const char *tag,
const gchar *format,
const void *data,
guint32 size) {
xmlNodePtr value_xml;
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!format) return(FALSE);
if(!data) return(FALSE);
value_xml = xmlNewChild(p, NULL, tag, NULL);
if(!value_xml) return(FALSE);
if(size == 0) return(TRUE);
if(0 == strcmp(format, "hex")) {
/* Write out the chars as hex, buffering them in max 64 character
lines. I was going to use xmlNewTextChild, and xmlTextConcat,
but that doesn't seem to work, and looking at the source,
xmlNewTextChild doesn't set the node type to a type that
xmlTextConcat will recognize and allow. */
const guint max_line_len = 64;
xmlNodePtr data_xml = NULL;
GString *output;
guint32 i;
output = g_string_sized_new(max_line_len + 2);
for(i = 0; i < size; i++) {
g_string_sprintfa(output, "%x", (int) (((char *) data)[i]));
if(((i + 1) % max_line_len) == 0) {
data_xml = xmlNewChild(value_xml, NULL, "hex", output->str);
if(!data_xml) {
return(FALSE);
g_string_free(output, TRUE);
}
g_string_truncate(output, 0);
}
}
if(strlen(output->str) > 0) {
data_xml = xmlNewChild(value_xml, NULL, "hex", output->str);
if(!data_xml) {
g_string_free(output, TRUE);
return(FALSE);
}
}
g_string_free(output, TRUE);
} else {
fprintf(stderr, "xml_add_binary: unknown output format %s.\n", format);
return(FALSE);
}
return(TRUE);
}
static gboolean xml_add_kvp_value(xmlNodePtr p, kvp_value *val);
static gboolean
xml_add_kvp_glist(xmlNodePtr p, const char *tag, GList *lst) {
xmlNodePtr list_xml;
GList *cursor;
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!lst) return(FALSE);
list_xml = xmlNewChild(p, NULL, tag, NULL);
if(!list_xml) return(FALSE);
for(cursor = lst; cursor; cursor = cursor->next) {
kvp_value * val = (kvp_value *) cursor->data;
if(!xml_add_kvp_value(list_xml, val)) {
return(FALSE);
}
}
return(TRUE);
}
static gboolean
xml_add_kvp_frame(xmlNodePtr p, const char *tag,
const kvp_frame *kvpf,
gboolean add_if_empty);
static gboolean
xml_add_kvp_value(xmlNodePtr p, kvp_value *val) {
if(!p) return(FALSE);
if(!val) return(FALSE);
switch(kvp_value_get_type(val)) {
case KVP_TYPE_GINT64:
return(xml_add_gint64(p, "gint64", kvp_value_get_gint64(val)));
break;
case KVP_TYPE_DOUBLE:
return(xml_add_double(p, "double", kvp_value_get_double(val)));
break;
case KVP_TYPE_STRING:
return(xml_add_str(p, "string", kvp_value_get_string(val), TRUE));
break;
case KVP_TYPE_GUID:
return(xml_add_guid(p, "guid", kvp_value_get_guid(val)));
break;
case KVP_TYPE_BINARY:
{
guint64 size;
void *binary_data = kvp_value_get_binary(val, &size);
if(!binary_data) return(FALSE);
return(xml_add_binary(p, "binary", "hex", binary_data, size));
}
break;
case KVP_TYPE_GLIST:
return(xml_add_kvp_glist(p, "glist", kvp_value_get_glist(val)));
break;
case KVP_TYPE_FRAME:
return(xml_add_kvp_frame(p, "frame", kvp_value_get_frame(val), TRUE));
break;
default:
return(FALSE);
break;
};
return(TRUE);
}
static gboolean
xml_add_kvp_slot(xmlNodePtr p, const char *key, kvp_value *val) {
xmlNodePtr slot_xml;
xmlNodePtr key_xml;
if(!p) return(FALSE);
if(!key) return(FALSE);
if(!val) return(FALSE);
slot_xml = xmlNewChild(p, NULL, "s", NULL);
if(!slot_xml) return(FALSE);
key_xml = xmlNewChild(slot_xml, NULL, "k", key);
if(!key_xml) return(FALSE);
return(xml_add_kvp_value(slot_xml, val));
}
typedef struct {
xmlNodePtr node;
gint64 keycount;
} kvp_value_foreach_info;
static void
xml_add_kvp_value_foreach_adapter(const char *key,
kvp_value *value,
gpointer data) {
kvp_value_foreach_info *info = (kvp_value_foreach_info *) data;
xml_add_kvp_slot(info->node, key, value);
info->keycount++;
}
static gboolean
xml_add_kvp_frame(xmlNodePtr p,
const char *tag,
const kvp_frame *kvpf,
gboolean add_if_empty) {
xmlNodePtr kvp_xml;
kvp_value_foreach_info info;
if(!p) return(FALSE);
if(!tag) return(FALSE);
if(!kvpf) return(FALSE);
kvp_xml = xmlNewNode(NULL, tag);
if(!kvp_xml) return(FALSE);
info.node = kvp_xml;
info.keycount = 0;
kvp_frame_for_each_slot((kvp_frame *) kvpf,
xml_add_kvp_value_foreach_adapter,
&info);
if(add_if_empty || info.keycount) {
xmlAddChild(p, kvp_xml);
} else {
xmlFreeNode(kvp_xml);
}
return(TRUE);
}
static gboolean
xml_add_transaction_split(xmlNodePtr p, Split* s) {
xmlNodePtr split_xml;
if(!p) return(FALSE);
if(!s) return(FALSE);
split_xml = xmlNewChild(p, NULL, "split", NULL);
if(!split_xml) return(FALSE);
if(!xml_add_guid(split_xml, "guid", xaccSplitGetGUID(s)))
return(FALSE);
if(!xml_add_str(split_xml, "memo", xaccSplitGetMemo(s), FALSE))
return(FALSE);
if(!xml_add_str(split_xml, "action", xaccSplitGetAction(s), FALSE))
return(FALSE);
/* reconcile-state */
{
char state = xaccSplitGetReconcile(s);
if(!xml_add_character(split_xml, "reconcile-state", state))
return(FALSE);
}
{
/* reconcile-date */
Timespec ts;
xaccSplitGetDateReconciledTS(s, &ts);
if(!xml_add_editable_timespec(split_xml, "reconcile-date", &ts, FALSE))
return(FALSE);
}
/* share-amount */
if(!xml_add_gnc_numeric(split_xml, "value", xaccSplitGetValue(s)))
return(FALSE);
/* share-price */
if(!xml_add_gnc_numeric(split_xml, "quantity", xaccSplitGetShareAmount(s)))
return(FALSE);
/* account */
{
Account *acct = xaccSplitGetAccount(s);
if(acct) {
if(!xml_add_guid(split_xml, "account", xaccAccountGetGUID(acct)))
return(FALSE);
}
}
#if 0
{
gchar data[] = "DEADBEEF";
GList *lst = NULL;
kvp_frame *f = kvp_frame_new();
kvp_value *val1 = kvp_value_new_binary(data, sizeof(data) - 1);
kvp_value *val2 = kvp_value_new_gint64(666);
kvp_value *val3 = kvp_value_new_string("foo");
kvp_frame_set_slot(f, "slot-1", val1);
kvp_frame_set_slot(f, "slot-2", val2);
kvp_frame_set_slot(f, "slot-3", val3);
lst = g_list_append(lst, val1);
lst = g_list_append(lst, val2);
lst = g_list_append(lst, val3);
xaccSplitSetSlot(s, "one", val1);
xaccSplitSetSlot(s, "two", val2);
xaccSplitSetSlot(s, "three", val3);
xaccSplitSetSlot(s, "listness", kvp_value_new_glist(lst));
xaccSplitSetSlot(s, "subbyslot", kvp_value_new_frame(f));
}
#endif
if(s->kvp_data) {
if(!xml_add_kvp_frame(split_xml, "slots", s->kvp_data, FALSE))
return(FALSE);
}
return(TRUE);
}
static gboolean
xml_add_txn_restore(xmlNodePtr p, Transaction* t) {
xmlNodePtr txn_xml;
xmlNodePtr restore_xml;
if(!p) return(FALSE);
if(!t) return(FALSE);
txn_xml = xmlNewChild(p, NULL, "transaction", NULL);
if(!txn_xml) return(FALSE);
restore_xml = xmlNewChild(txn_xml, NULL, "restore", NULL);
if(!restore_xml) return(FALSE);
if(!xml_add_guid(restore_xml, "guid", xaccTransGetGUID(t)))
return(FALSE);
if(!xml_add_str(restore_xml, "num", xaccTransGetNum(t), FALSE))
return(FALSE);
{
Timespec ts;
xaccTransGetDatePostedTS(t, &ts);
if(!xml_add_editable_timespec(restore_xml, "date-posted", &ts, FALSE))
return(FALSE);
}
{
Timespec ts;
xaccTransGetDateEnteredTS(t, &ts);
if(!xml_add_editable_timespec(restore_xml, "date-entered", &ts, FALSE))
return(FALSE);
}
if(!xml_add_str(restore_xml, "description", xaccTransGetDescription(t), FALSE))
return(FALSE);
if(t->kvp_data) {
if(!xml_add_kvp_frame(restore_xml, "slots", t->kvp_data, FALSE))
return(FALSE);
}
{
guint32 n = 0;
Split *s = xaccTransGetSplit(t, n);
while(s) {
if(!xml_add_transaction_split(restore_xml, s)) return(FALSE);
n++;
s = xaccTransGetSplit(t, n);
}
}
return(TRUE);
}
static gboolean
xml_add_txn_restore_adapter(Transaction *t, gpointer data) {
xmlNodePtr xml_node = (xmlNodePtr) data;
return(xml_add_txn_restore(xml_node, t));
}
static gboolean
xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g) {
return(xaccGroupForEachTransaction(g,
xml_add_txn_restore_adapter,
(gpointer) p));
}
static gboolean
xml_add_account_restorer(xmlNodePtr p, Account* a) {
xmlNodePtr acct_xml;
if(!p) return(FALSE);
if(!a) return(FALSE);
acct_xml = xmlNewChild(p, NULL, "account", NULL);
if(!acct_xml) return(FALSE);
acct_xml = xmlNewChild(acct_xml, NULL, "restore", NULL);
if(!acct_xml) return(FALSE);
if(!xml_add_str(acct_xml, "name",
xaccAccountGetName(a), FALSE))
return(FALSE);
if(!xml_add_guid(acct_xml, "guid",
xaccAccountGetGUID(a)))
return(FALSE);
if(!xml_add_str(acct_xml, "type",
xaccAccountTypeEnumAsString(xaccAccountGetType(a)), FALSE))
return(FALSE);
if(!xml_add_str(acct_xml, "code",
xaccAccountGetCode(a), FALSE))
return(FALSE);
if(!xml_add_str(acct_xml, "description",
xaccAccountGetDescription(a), FALSE))
return(FALSE);
/* Notes field is now in kvp table. */
if(!xml_add_commodity_ref(acct_xml, "currency", xaccAccountGetCurrency(a)))
return(FALSE);
if(!xml_add_commodity_ref(acct_xml, "security", xaccAccountGetSecurity(a)))
return(FALSE);
if(a->kvp_data) {
if(!xml_add_kvp_frame(acct_xml, "slots", a->kvp_data, FALSE))
return(FALSE);
}
{
Account *parent = xaccAccountGetParentAccount(a);
if(parent) {
xmlNodePtr parent_xml = xmlNewChild(acct_xml, NULL, "parent", NULL);
if(!parent_xml) return(FALSE);
if(!xml_add_guid(parent_xml, "guid", xaccAccountGetGUID(parent)))
return(FALSE);
}
}
{
AccountGroup *g = xaccAccountGetChildren(a);
if(g) {
guint32 num_accounts = xaccGroupGetNumAccounts(g);
guint32 i = 0;
while(i < num_accounts) {
Account *current_acc = xaccGroupGetAccount(g, i);
if(!xml_add_account_restorer(p, current_acc)) return(FALSE);
i++;
}
}
}
return(TRUE);
}
static gboolean
xml_add_account_restorers(xmlNodePtr p, AccountGroup *g) {
guint32 i = 0;
guint32 num_accounts;
if(!p) return(FALSE);
if(!g) return(FALSE);
num_accounts = xaccGroupGetNumAccounts(g);
while(i < num_accounts) {
Account *current_acc = xaccGroupGetAccount(g, i);
xml_add_account_restorer(p, current_acc);
i++;
}
return(TRUE);
}
gboolean
gncxml_write(AccountGroup *group, const gchar *filename) {
/* fixme: this should be broken up into sub-functions later. */
xmlDocPtr doc;
xmlNodePtr ledger_data;
xmlNodePtr tmpnode;
int status;
doc = xmlNewDoc("1.0");
doc->root = xmlNewDocNode(doc, NULL, "gnc", NULL);
tmpnode = xmlNewChild(doc->root, NULL, "version", "1");
if(!tmpnode) {
xmlFreeDoc(doc);
return FALSE;
}
ledger_data = xmlNewChild(doc->root, NULL, "ledger-data", NULL);
if(!ledger_data) {
xmlFreeDoc(doc);
return FALSE;
}
if(!xml_add_commodity_restorers(ledger_data)) {
xmlFreeDoc(doc);
return FALSE;
}
if(!xml_add_account_restorers(ledger_data, group)) {
xmlFreeDoc(doc);
return FALSE;
}
if(!xml_add_txn_and_split_restorers(ledger_data, group)) {
xmlFreeDoc(doc);
return FALSE;
}
xmlIndentTreeOutput = TRUE;
status = xmlSaveFile(filename, doc);
xmlFreeDoc(doc);
/* FIXME: This gives me a non-zero result, even when everything's fine ???
status = xmlDocDump(outfile, doc);
This crashes with the current libxml, but they don't document that
they close the file, so I don't know why...
assert(fclose(outfile) == 0);
*/
return(status != -1);
}

12
src/engine/io-gncxml.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __IO_GNCXML_H__
#define __IO_GNCXML_H__
#include <glib.h>
#include "Group.h"
gboolean gncxml_read(const gchar *name, AccountGroup **result_group);
gboolean gncxml_write(AccountGroup *group, const gchar *name);
gboolean is_gncxml_file(const gchar *name);
#endif

View File

@ -25,64 +25,32 @@
#include "guid.h"
#include <string.h>
#include <stdio.h>
#include <glib.h>
struct _kvp_frame {
GHashTable * hash;
};
struct _kvp_list {
GList * list;
};
struct _kvp_value_int64 {
kvp_value_t type;
gint64 value;
};
struct _kvp_value_float64 {
kvp_value_t type;
double value;
};
struct _kvp_value_string {
kvp_value_t type;
char * value;
};
struct _kvp_value_guid {
kvp_value_t type;
GUID * value;
};
struct _kvp_value_binary {
kvp_value_t type;
void * value;
typedef struct {
void *data;
int datasize;
};
} kvp_value_binary_data;
struct _kvp_value_frame {
struct _kvp_value {
kvp_value_t type;
kvp_frame * value;
union {
gint64 int64;
double dbl;
gchar *str;
GUID *guid;
kvp_value_binary_data binary;
GList *list;
kvp_frame *frame;
} value;
};
struct _kvp_value_list {
kvp_value_t type;
kvp_list * value;
};
union _kvp_value {
kvp_value_t type;
struct _kvp_value_int64 int64;
struct _kvp_value_float64 float64;
struct _kvp_value_string str;
struct _kvp_value_guid guid;
struct _kvp_value_binary binary;
struct _kvp_value_list list;
struct _kvp_value_frame frame;
};
/********************************************************************
* kvp_frame functions
********************************************************************/
@ -97,11 +65,20 @@ kvp_comp_func(gconstpointer v, gconstpointer v2) {
return g_str_equal(v, v2);
}
static gboolean
init_frame_body_if_needed(kvp_frame *f) {
if(!f->hash) {
f->hash = g_hash_table_new(&kvp_hash_func,
&kvp_comp_func);
}
return(f->hash != NULL);
}
kvp_frame *
kvp_frame_new(void) {
kvp_frame * retval = g_new0(kvp_frame, 1);
retval->hash = g_hash_table_new(&kvp_hash_func,
&kvp_comp_func);
/* save space until we have data */
retval->hash = NULL;
return retval;
}
@ -113,13 +90,15 @@ kvp_frame_delete_worker(gpointer key, gpointer value, gpointer user_data) {
void
kvp_frame_delete(kvp_frame * frame) {
/* free any allocated resource for frame or its children */
g_hash_table_foreach(frame->hash, & kvp_frame_delete_worker,
(gpointer)frame);
/* delete the hash table */
g_hash_table_destroy(frame->hash);
frame->hash = NULL;
if(frame->hash) {
/* free any allocated resource for frame or its children */
g_hash_table_foreach(frame->hash, & kvp_frame_delete_worker,
(gpointer)frame);
/* delete the hash table */
g_hash_table_destroy(frame->hash);
frame->hash = NULL;
}
g_free(frame);
}
@ -136,197 +115,122 @@ kvp_frame_copy_worker(gpointer key, gpointer value, gpointer user_data) {
kvp_frame *
kvp_frame_copy(const kvp_frame * frame) {
kvp_frame * retval = kvp_frame_new();
g_hash_table_foreach(frame->hash,
& kvp_frame_copy_worker,
(gpointer)retval);
if(frame->hash) {
if(!init_frame_body_if_needed(retval)) return(NULL);
g_hash_table_foreach(frame->hash,
& kvp_frame_copy_worker,
(gpointer)retval);
}
return retval;
}
void
kvp_frame_set_slot(kvp_frame * frame, const char * slot,
const kvp_value * value) {
static void
kvp_frame_set_slot_destructively(kvp_frame * frame, const char * slot,
kvp_value * new_value) {
/* FIXME: no way to indicate errors... */
gpointer orig_key;
gpointer orig_value;
gpointer new_value;
int key_exists;
new_value = kvp_value_copy(value);
if(!new_value && !frame->hash) return; /* don't need to do anything */
if(!init_frame_body_if_needed(frame)) return;
g_hash_table_freeze(frame->hash);
key_exists = g_hash_table_lookup_extended(frame->hash, slot,
& orig_key, & orig_value);
if (key_exists) {
if(key_exists) {
g_hash_table_remove(frame->hash, slot);
g_free(orig_key);
kvp_value_delete(orig_value);
}
g_hash_table_insert(frame->hash, g_strdup(slot), new_value);
if(new_value) g_hash_table_insert(frame->hash, g_strdup(slot), new_value);
g_hash_table_thaw(frame->hash);
}
void
kvp_frame_set_slot(kvp_frame * frame, const char * slot,
const kvp_value * value) {
/* FIXME: no way to indicate errors... */
kvp_value *new_value = NULL;
if(value) new_value = kvp_value_copy(value);
kvp_frame_set_slot_destructively(frame, slot, new_value);
}
kvp_value *
kvp_frame_get_slot(kvp_frame * frame, const char * slot) {
if(!frame->hash) return(NULL);
return (kvp_value *)g_hash_table_lookup(frame->hash, slot);
}
/********************************************************************
* kvp_list functions
* kvp glist functions
********************************************************************/
kvp_list *
kvp_list_new(void) {
kvp_list * retval = g_new0(kvp_list, 1);
retval->list = NULL;
return retval;
}
static void
kvp_list_delete_worker(gpointer datum, gpointer user_data) {
kvp_glist_delete_worker(gpointer datum, gpointer user_data) {
kvp_value * val = (kvp_value *)datum;
kvp_value_delete(val);
}
void
kvp_list_delete(kvp_list * list) {
if(list) {
if(list->list) {
/* delete the data in the list */
g_list_foreach(list->list, & kvp_list_delete_worker, NULL);
/* free the backbone */
g_list_free(list->list);
}
g_free(list);
kvp_glist_delete(GList * list) {
if(list) {
/* delete the data in the list */
g_list_foreach(list, & kvp_glist_delete_worker, NULL);
/* free the backbone */
g_list_free(list);
}
}
kvp_list *
kvp_list_copy(const kvp_list * list) {
kvp_list * retval = kvp_list_new();
GList *
kvp_glist_copy(const GList * list) {
GList * retval = NULL;
GList * lptr;
if(!list) return retval;
/* duplicate the backbone of the list (this duplicates the POINTERS
* to the values; we need to deep-copy the values separately) */
retval->list = g_list_copy(list->list);
retval = g_list_copy((GList *) list);
/* this step deep-copies the values */
for(lptr = retval->list; lptr; lptr = lptr->next) {
for(lptr = retval; lptr; lptr = lptr->next) {
lptr->data = kvp_value_copy(lptr->data);
}
return retval;
}
gboolean
kvp_list_null_p(const kvp_list * list) {
return (!list || (list->list == NULL));
}
gint
kvp_glist_compare(const GList * list1, const GList * list2) {
const GList *lp1;
const GList *lp2;
kvp_value *
kvp_list_car(kvp_list * list) {
if(!list || (list->list == NULL)) {
return NULL;
if(list1 == list2) return 0;
/* nothing is always less than something */
if(!list1 && list2) return -1;
if(list1 && !list2) return 1;
lp1 = list1;
lp2 = list2;
while(lp1 && lp2) {
kvp_value *v1 = (kvp_value *) lp1->data;
kvp_value *v2 = (kvp_value *) lp2->data;
gint vcmp = kvp_value_compare(v1, v2);
if(vcmp != 0) return vcmp;
lp1 = lp1->next;
lp2 = lp2->next;
}
else {
return (kvp_value *)(list->list->data);
}
}
kvp_list *
kvp_list_cdr(kvp_list * list) {
kvp_list * retval;
if(!list || (list->list == NULL)) {
return NULL;
}
else {
retval = kvp_list_new();
retval->list = list->list->next;
return retval;
}
}
/* cons semantics are "hand over": you give it pointers to
* your objects and the list handles them after that. */
kvp_list *
kvp_list_cons(kvp_value * car, kvp_list * cdr) {
kvp_list * retval;
if(!car || !cdr) {
return NULL;
}
else {
retval = kvp_list_new();
retval->list = g_list_prepend( cdr->list, (gpointer)car);
cdr->list = NULL;
kvp_list_delete(cdr);
return retval;
}
}
kvp_list *
kvp_list_1(kvp_value * value) {
kvp_list * retval = kvp_list_new();
retval = kvp_list_cons(value, retval);
return retval;
}
kvp_list *
kvp_list_2(kvp_value * value1, kvp_value * value2) {
kvp_list * retval = kvp_list_new();
retval = kvp_list_cons(value2, retval);
retval = kvp_list_cons(value1, retval);
return retval;
}
kvp_list *
kvp_list_3(kvp_value * value1, kvp_value * value2,
kvp_value * value3) {
kvp_list * retval = kvp_list_new();
retval = kvp_list_cons(value3, retval);
retval = kvp_list_cons(value2, retval);
retval = kvp_list_cons(value1, retval);
return retval;
}
kvp_list *
kvp_list_4(kvp_value * value1, kvp_value * value2,
kvp_value * value3, kvp_value * value4) {
kvp_list * retval = kvp_list_new();
retval = kvp_list_cons(value4, retval);
retval = kvp_list_cons(value3, retval);
retval = kvp_list_cons(value2, retval);
retval = kvp_list_cons(value1, retval);
return retval;
}
kvp_list *
kvp_list_5(kvp_value * value1, kvp_value * value2,
kvp_value * value3, kvp_value * value4,
kvp_value * value5) {
kvp_list * retval = kvp_list_new();
retval = kvp_list_cons(value5, retval);
retval = kvp_list_cons(value4, retval);
retval = kvp_list_cons(value3, retval);
retval = kvp_list_cons(value2, retval);
retval = kvp_list_cons(value1, retval);
return retval;
if(!lp1 && lp2) return -1;
if(!lp2) return 1;
return 0;
}
/********************************************************************
@ -334,25 +238,18 @@ kvp_list_5(kvp_value * value1, kvp_value * value2,
********************************************************************/
kvp_value *
kvp_value_new(void) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_NONE;
return retval;
}
kvp_value *
kvp_value_new_int64(gint64 value) {
kvp_value_new_gint64(gint64 value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_INT64;
retval->int64.value = value;
retval->type = KVP_TYPE_GINT64;
retval->value.int64 = value;
return retval;
}
kvp_value *
kvp_value_new_float64(double value) {
kvp_value_new_double(double value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_FLOAT64;
retval->float64.value = value;
retval->type = KVP_TYPE_DOUBLE;
retval->value.dbl = value;
return retval;
}
@ -360,7 +257,7 @@ kvp_value *
kvp_value_new_string(const char * value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_STRING;
retval->str.value = g_strdup(value);
retval->value.str = g_strdup(value);
return retval;
}
@ -368,34 +265,51 @@ kvp_value *
kvp_value_new_guid(const GUID * value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_GUID;
retval->guid.value = g_new0(GUID, 1);
memcpy(retval->guid.value, value, sizeof(GUID));
retval->value.guid = g_new0(GUID, 1);
memcpy(retval->value.guid, value, sizeof(GUID));
return retval;
}
kvp_value *
kvp_value_new_binary(const void * value, int datasize) {
kvp_value_new_binary(const void * value, guint64 datasize) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_BINARY;
retval->binary.value = g_new0(char, datasize);
retval->binary.datasize = datasize;
memcpy(retval->binary.value, value, datasize);
retval->type = KVP_TYPE_BINARY;
retval->value.binary.data = g_new0(char, datasize);
retval->value.binary.datasize = datasize;
memcpy(retval->value.binary.data, value, datasize);
return retval;
}
kvp_value *
kvp_value_new_list(const kvp_list * value) {
kvp_value_new_binary_nc(void * value, guint64 datasize) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_LIST;
retval->list.value = kvp_list_copy(value);
retval->type = KVP_TYPE_BINARY;
retval->value.binary.data = value;
retval->value.binary.datasize = datasize;
return retval;
}
kvp_value *
kvp_value_new_glist(const GList * value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_GLIST;
retval->value.list = kvp_glist_copy(value);
return retval;
}
kvp_value *
kvp_value_new_glist_nc(GList * value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_GLIST;
retval->value.list = value;
return retval;
}
kvp_value *
kvp_value_new_frame(const kvp_frame * value) {
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_FRAME;
retval->frame.value = kvp_frame_copy(value);
kvp_value * retval = g_new0(kvp_value, 1);
retval->type = KVP_TYPE_FRAME;
retval->value.frame = kvp_frame_copy(value);
return retval;
}
@ -405,25 +319,25 @@ kvp_value_delete(kvp_value * value) {
switch(value->type) {
case KVP_TYPE_STRING:
g_free(value->str.value);
g_free(value->value.str);
break;
case KVP_TYPE_GUID:
g_free(value->guid.value);
g_free(value->value.guid);
break;
case KVP_TYPE_BINARY:
g_free(value->binary.value);
g_free(value->value.binary.data);
break;
case KVP_TYPE_LIST:
kvp_list_delete(value->list.value);
case KVP_TYPE_GLIST:
kvp_glist_delete(value->value.list);
break;
case KVP_TYPE_FRAME:
kvp_frame_delete(value->frame.value);
kvp_frame_delete(value->value.frame);
break;
case KVP_TYPE_NONE:
case KVP_TYPE_INT64:
case KVP_TYPE_FLOAT64:
case KVP_TYPE_GINT64:
case KVP_TYPE_DOUBLE:
default:
break;
}
g_free(value);
}
@ -434,9 +348,9 @@ kvp_value_get_type(const kvp_value * value) {
}
gint64
kvp_value_get_int64(const kvp_value * value) {
if(value->type == KVP_TYPE_INT64) {
return value->int64.value;
kvp_value_get_gint64(const kvp_value * value) {
if(value->type == KVP_TYPE_GINT64) {
return value->value.int64;
}
else {
return 0;
@ -444,9 +358,9 @@ kvp_value_get_int64(const kvp_value * value) {
}
double
kvp_value_get_float64(const kvp_value * value) {
if(value->type == KVP_TYPE_FLOAT64) {
return value->float64.value;
kvp_value_get_double(const kvp_value * value) {
if(value->type == KVP_TYPE_DOUBLE) {
return value->value.dbl;
}
else {
return 0.0;
@ -456,7 +370,7 @@ kvp_value_get_float64(const kvp_value * value) {
char *
kvp_value_get_string(const kvp_value * value) {
if(value->type == KVP_TYPE_STRING) {
return value->str.value;
return value->value.str;
}
else {
return NULL;
@ -466,7 +380,7 @@ kvp_value_get_string(const kvp_value * value) {
GUID *
kvp_value_get_guid(const kvp_value * value) {
if(value->type == KVP_TYPE_GUID) {
return value->guid.value;
return value->value.guid;
}
else {
return NULL;
@ -474,10 +388,10 @@ kvp_value_get_guid(const kvp_value * value) {
}
void *
kvp_value_get_binary(const kvp_value * value, int * size_return) {
kvp_value_get_binary(const kvp_value * value, guint64 * size_return) {
if(value->type == KVP_TYPE_BINARY) {
*size_return = value->binary.datasize;
return value->binary.value;
*size_return = value->value.binary.datasize;
return value->value.binary.data;
}
else {
*size_return = 0;
@ -485,10 +399,10 @@ kvp_value_get_binary(const kvp_value * value, int * size_return) {
}
}
kvp_list *
kvp_value_get_list(const kvp_value * value) {
if(value->type == KVP_TYPE_LIST) {
return value->list.value;
GList *
kvp_value_get_glist(const kvp_value * value) {
if(value->type == KVP_TYPE_GLIST) {
return value->value.list;
}
else {
return NULL;
@ -498,45 +412,158 @@ kvp_value_get_list(const kvp_value * value) {
kvp_frame *
kvp_value_get_frame(const kvp_value * value) {
if(value->type == KVP_TYPE_FRAME) {
return value->frame.value;
return value->value.frame;
}
else {
return NULL;
}
}
/* manipulators */
#if 0
/* untested - didn't end up needing it... */
gboolean
kvp_value_binary_append(kvp_value *kv, void *data, guint64 size) {
void *new_data;
guint64 new_size;
if(kv->type != KVP_TYPE_BINARY) return(FALSE);
new_size = kv->value.binary.datasize + size;
new_data = g_realloc(kv->value.binary.data, new_size);
if(!new_data) return(FALSE);
memcpy(kv->value.binary.data + kv->value.binary.datasize, data, size);
kv->value.binary.datasize = new_size;
return(TRUE);
}
#endif
kvp_value *
kvp_value_copy(const kvp_value * value) {
if(!value) return NULL;
switch(value->type) {
case KVP_TYPE_INT64:
return kvp_value_new_int64(value->int64.value);
case KVP_TYPE_GINT64:
return kvp_value_new_gint64(value->value.int64);
break;
case KVP_TYPE_FLOAT64:
return kvp_value_new_float64(value->float64.value);
case KVP_TYPE_DOUBLE:
return kvp_value_new_double(value->value.dbl);
break;
case KVP_TYPE_STRING:
return kvp_value_new_string(value->str.value);
return kvp_value_new_string(value->value.str);
break;
case KVP_TYPE_GUID:
return kvp_value_new_guid(value->guid.value);
return kvp_value_new_guid(value->value.guid);
break;
case KVP_TYPE_BINARY:
return kvp_value_new_binary(value->binary.value,
value->binary.datasize);
return kvp_value_new_binary(value->value.binary.data,
value->value.binary.datasize);
break;
case KVP_TYPE_LIST:
return kvp_value_new_list(value->list.value);
case KVP_TYPE_GLIST:
return kvp_value_new_glist(value->value.list);
break;
case KVP_TYPE_FRAME:
return kvp_value_new_frame(value->frame.value);
break;
case KVP_TYPE_NONE:
return kvp_value_new();
return kvp_value_new_frame(value->value.frame);
break;
}
return NULL;
}
void
kvp_frame_for_each_slot(kvp_frame *f,
void (*proc)(const char *key,
kvp_value *value,
gpointer data),
gpointer data) {
if(!f) return;
if(!proc) return;
if(!(f->hash)) return;
g_hash_table_foreach(f->hash, (GHFunc) proc, data);
}
gboolean
kvp_value_compare(const kvp_value * kva, const kvp_value * kvb) {
if(kva == kvb) return 0;
/* nothing is always less than something */
if(!kva && kvb) return -1;
if(kva && !kvb) return 1;
if(kva->type < kvb->type) return -1;
if(kva->type > kvb->type) return 1;
switch(kva->type) {
case KVP_TYPE_GINT64:
case KVP_TYPE_DOUBLE:
if(kva->value.int64 < kvb->value.int64) return -1;
if(kva->value.int64 > kvb->value.int64) return -1;
return 0;
break;
case KVP_TYPE_STRING:
return strcmp(kva->value.str, kvb->value.str);
break;
case KVP_TYPE_GUID:
return guid_compare(kva->value.guid, kvb->value.guid);
break;
case KVP_TYPE_BINARY:
if(kva->value.binary.datasize < kvb->value.binary.datasize) return -1;
if(kva->value.binary.datasize < kvb->value.binary.datasize) return 1;
return memcmp(kva->value.binary.data,
kvb->value.binary.data,
kva->value.binary.datasize);
break;
case KVP_TYPE_GLIST:
return kvp_glist_compare(kva->value.list, kvb->value.list);
break;
case KVP_TYPE_FRAME:
return kvp_frame_compare(kva->value.frame, kvb->value.frame);
break;
}
fprintf(stderr, "DANGER: reached unreachable code (kvp_value_equal).\n");
return FALSE;
}
typedef struct {
gint compare;
kvp_frame *other_frame;
} kvp_frame_cmp_status;
static void
kvp_frame_compare_helper(const char *key, kvp_value* val, gpointer data) {
kvp_frame_cmp_status *status = (kvp_frame_cmp_status *) data;
if(status->compare == 0) {
kvp_frame *other_frame = status->other_frame;
kvp_value *other_val = kvp_frame_get_slot(other_frame, key);
if(other_val) {
status->compare = kvp_value_compare(val, other_val);
} else {
status->compare = 1;
}
}
}
gint
kvp_frame_compare(const kvp_frame *fa, const kvp_frame *fb) {
kvp_frame_cmp_status status;
if(fa == fb) return 0;
/* nothing is always less than something */
if(!fa && fb) return -1;
if(fa && !fb) return 1;
/* nothing is always less than something */
if(!fa->hash && fb->hash) return -1;
if(fa->hash && !fb->hash) return 1;
status.compare = 0;
status.other_frame = (kvp_frame *) fb;
kvp_frame_for_each_slot((kvp_frame *) fa, kvp_frame_compare_helper, &status);
return(status.compare);
}

View File

@ -34,73 +34,95 @@
*
* Pointers passed as arguments into set_slot and get_slot are the
* responsibility of the caller. Pointers returned by get_slot are
* the responsibility of the caller (they point to newly-allocated
* structures which are deep value copies of those in the frame).
* owned by the kvp_frame. Make copies as needed.
*
* kvp_frame_delete and kvp_value_delete are deep (recursive) deletes.
* kvp_frame_copy and kvp_value_copy are deep value copies. */
typedef enum { KVP_TYPE_NONE,
KVP_TYPE_INT64, KVP_TYPE_FLOAT64,
KVP_TYPE_STRING, KVP_TYPE_GUID, KVP_TYPE_BINARY,
KVP_TYPE_LIST, KVP_TYPE_FRAME } kvp_value_t;
typedef enum {
KVP_TYPE_GINT64,
KVP_TYPE_DOUBLE,
KVP_TYPE_STRING,
KVP_TYPE_GUID,
KVP_TYPE_BINARY,
KVP_TYPE_GLIST,
KVP_TYPE_FRAME
} kvp_value_t;
typedef struct _kvp_frame kvp_frame;
typedef struct _kvp_list kvp_list;
typedef union _kvp_value kvp_value;
#if 0
typedef union _kvp_value kvp_value;
#else
typedef struct _kvp_value kvp_value;
#endif
/* kvp_frame functions */
kvp_frame * kvp_frame_new(void);
void kvp_frame_delete(kvp_frame * frame);
void kvp_frame_delete(kvp_frame * frame);
kvp_frame * kvp_frame_copy(const kvp_frame * frame);
void kvp_frame_set_slot(kvp_frame * frame,
void kvp_frame_set_slot(kvp_frame * frame,
const char * key, const kvp_value * value);
kvp_value * kvp_frame_get_slot(kvp_frame * frame,
const char * key);
kvp_value * kvp_value_new(void);
void kvp_value_delete(kvp_value * value);
gint kvp_frame_compare(const kvp_frame *fa, const kvp_frame *fb);
void kvp_value_delete(kvp_value * value);
kvp_value * kvp_value_copy(const kvp_value * value);
gint kvp_value_compare(const kvp_value *va, const kvp_value *vb);
/* kvp_list functions */
kvp_list * kvp_list_new(void);
void kvp_list_delete(kvp_list * list);
kvp_list * kvp_list_copy(const kvp_list * list);
gboolean kvp_list_null_p(const kvp_list * list);
/* list convenience funcs. */
gint kvp_glist_compare(const GList * list1, const GList * list2);
kvp_value * kvp_list_car(kvp_list * list);
kvp_list * kvp_list_cdr(kvp_list * list);
kvp_list * kvp_list_cons(kvp_value * car, kvp_list * cdr);
kvp_list * kvp_list_1(kvp_value * value);
kvp_list * kvp_list_2(kvp_value * value1, kvp_value * value2);
kvp_list * kvp_list_3(kvp_value * value1, kvp_value * value2,
kvp_value * value3);
kvp_list * kvp_list_4(kvp_value * value1, kvp_value * value2,
kvp_value * value3, kvp_value * value4);
kvp_list * kvp_list_5(kvp_value * value1, kvp_value * value2,
kvp_value * value3, kvp_value * value4,
kvp_value * value5);
GList * kvp_glist_copy(const GList * list);
/* deep copy: same as mapping kvp_value_copy over the
elements and then copying the spine. */
void kvp_glist_delete(GList * list);
/* deep delete: same as mapping kvp_value_delete over the
elements and then deleting the GList. */
/* value constructors (copying for pointer args) */
kvp_value * kvp_value_new_int64(gint64 value);
kvp_value * kvp_value_new_float64(double value);
kvp_value * kvp_value_new_gint64(gint64 value);
kvp_value * kvp_value_new_double(double value);
kvp_value * kvp_value_new_string(const char * value);
kvp_value * kvp_value_new_guid(const GUID * guid);
kvp_value * kvp_value_new_binary(const void * data, int datasize);
kvp_value * kvp_value_new_list(const kvp_list * value);
kvp_value * kvp_value_new_binary(const void * data, guint64 datasize);
kvp_value * kvp_value_new_glist(const GList * value);
kvp_value * kvp_value_new_frame(const kvp_frame * value);
/* value constructors (non-copying - kvp_value takes pointer ownership)
values *must* have been allocated via glib allocators! (gnew, etc.) */
kvp_value * kvp_value_new_binary_nc(void * data, guint64 datasize);
kvp_value * kvp_value_new_glist_nc(GList *lst);
/* value accessors (NON-copying for frames/lists/guids/binary) */
kvp_value_t kvp_value_get_type(const kvp_value * value);
gint64 kvp_value_get_int64(const kvp_value * value);
double kvp_value_get_float64(const kvp_value * value);
gint64 kvp_value_get_gint64(const kvp_value * value);
double kvp_value_get_double(const kvp_value * value);
char * kvp_value_get_string(const kvp_value * value);
GUID * kvp_value_get_guid(const kvp_value * value);
void * kvp_value_get_binary(const kvp_value * value,
int * size_return);
kvp_list * kvp_value_get_list(const kvp_value * value);
guint64 * size_return);
GList * kvp_value_get_glist(const kvp_value * value);
kvp_frame * kvp_value_get_frame(const kvp_value * value);
/* manipulators */
gboolean kvp_value_binary_append(kvp_value *v, void *data, guint64 size);
/* copying - but more efficient than creating a new kvp_value manually. */
/* iterators */
/* Traverse all of the slots in the given kvp_frame. This function
does not descend recursively to traverse any kvp_frames stored as
slot values. You must handle that in proc, with a suitable
recursive call if desired. */
void kvp_frame_for_each_slot(kvp_frame *f,
void (*proc)(const char *key,
kvp_value *value,
gpointer data),
gpointer data);
#endif

View File

@ -245,7 +245,7 @@ pgendCompareOneGroupOnly (PGBackend *be, AccountGroup *grp)
static void
pgendStoreOneAccountOnly (PGBackend *be, Account *acct, int update)
{
const char *acct_guid, *parent_guid, *child_guid;
const char *acct_guid, *parent_guid, *child_guid, *notes;
ENTER ("be=%p, acct=%p\n", be, acct);
if (!be || !acct) return;
@ -253,6 +253,10 @@ pgendStoreOneAccountOnly (PGBackend *be, Account *acct, int update)
parent_guid = guid_to_string(xaccGroupGetGUID (xaccAccountGetParent(acct)));
child_guid = guid_to_string(xaccGroupGetGUID (xaccAccountGetChildren(acct)));
/* This is technically incorrect since notes could be NULL */
notes = xaccAccountGetNotes(acct);
if(!notes) notes = "";
if (update) {
/* hack alert -- values should be escaped so that no '' apear in them */
snprintf (be->buff, be->bufflen,
@ -266,7 +270,7 @@ pgendStoreOneAccountOnly (PGBackend *be, Account *acct, int update)
xaccAccountGetName (acct),
xaccAccountGetCode (acct),
xaccAccountGetDescription (acct),
xaccAccountGetNotes (acct),
notes,
xaccAccountGetType (acct),
xaccAccountGetCurrency (acct),
xaccAccountGetSecurity (acct),
@ -315,7 +319,7 @@ pgendStoreOneAccountOnly (PGBackend *be, Account *acct, int update)
static int
pgendCompareOneAccountOnly (PGBackend *be, Account *acct)
{
const char *acct_guid;
const char *acct_guid, *notes;
PGresult *result;
int i=0, nrows=0, ndiffs=0;
@ -343,10 +347,13 @@ pgendCompareOneAccountOnly (PGBackend *be, Account *acct)
GET_RESULTS (be->connection, result);
IF_ONE_ROW (result, nrows, i) {
notes = xaccAccountGetNotes(acct);
if(!notes) notes = "";
/* compared queried values to input values */
COMP_STR ("accountName", xaccAccountGetName(acct), ndiffs);
COMP_STR ("description", xaccAccountGetDescription(acct), ndiffs);
COMP_STR ("notes", xaccAccountGetNotes(acct), ndiffs);
COMP_STR ("notes", notes, ndiffs);
COMP_STR ("currency", xaccAccountGetCurrency(acct), ndiffs);
COMP_STR ("security", xaccAccountGetSecurity(acct), ndiffs);
@ -504,8 +511,8 @@ pgendStoreOneSplitOnly (PGBackend *be, Split *split, int update)
xaccSplitGetMemo(split),
xaccSplitGetAction(split),
xaccSplitGetReconcile(split),
xaccSplitGetShareAmount(split),
xaccSplitGetSharePrice(split),
DxaccSplitGetShareAmount(split),
DxaccSplitGetSharePrice(split),
split_guid
);
} else {
@ -522,8 +529,8 @@ pgendStoreOneSplitOnly (PGBackend *be, Split *split, int update)
xaccSplitGetMemo(split),
xaccSplitGetAction(split),
xaccSplitGetReconcile(split),
xaccSplitGetShareAmount(split),
xaccSplitGetSharePrice(split)
DxaccSplitGetShareAmount(split),
DxaccSplitGetSharePrice(split)
);
}
free ((char *) split_guid);
@ -589,8 +596,8 @@ GET_DB_VAL("amount"),
GET_DB_VAL("share_price"));
/*
xaccSplitGetReconcile(split),
xaccSplitGetShareAmount(split),
xaccSplitGetSharePrice(split)
DxaccSplitGetShareAmount(split),
DxaccSplitGetSharePrice(split)
*/
}

View File

@ -25,6 +25,9 @@
* Author: Linas Vepstas (linas@linas.org) *
\********************************************************************/
#define _GNU_SOURCE
#include <string.h>
#include "config.h"
#ifdef HAVE_IEEEFP_H
@ -38,15 +41,13 @@
#include <locale.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "messages.h"
#include "gnc-engine.h"
#include "gnc-common.h"
#include "gnc-commodity.h"
#include "util.h"
/* hack alert -- stpcpy prototype is missing, use -DGNU */
char * stpcpy (char *dest, const char *src);
/** GLOBALS *********************************************************/
gncLogLevel loglevel[MOD_LAST + 1] =
{
@ -89,7 +90,7 @@ gnc_set_log_level_global(gncLogLevel level)
}
/* xaccParseAmount configuration */
/* DxaccParseAmount configuration */
static gboolean auto_decimal_enabled = FALSE;
static int auto_decimal_places = 2; /* default, can be changed */
@ -142,7 +143,7 @@ prettify (const char *name)
\********************************************************************/
#if DEBUG_MEMORY
// #if defined (__NetBSD__) || defined(__FreeBSD__)
/* #if defined (__NetBSD__) || defined(__FreeBSD__) */
#ifndef HAVE_MALLOC_USABLE_SIZE
#define malloc_usable_size(ptr) 0
@ -444,7 +445,7 @@ gnc_localeconv(void)
gnc_lconv_set(&lc.decimal_point, ".");
gnc_lconv_set(&lc.thousands_sep, ",");
gnc_lconv_set(&lc.grouping, "\003");
gnc_lconv_set(&lc.int_curr_symbol, "USD ");
gnc_lconv_set(&lc.int_curr_symbol, "USD");
gnc_lconv_set(&lc.currency_symbol, "$");
gnc_lconv_set(&lc.mon_decimal_point, ".");
gnc_lconv_set(&lc.mon_thousands_sep, ",");
@ -465,26 +466,19 @@ gnc_localeconv(void)
return &lc;
}
const char *
gnc_locale_default_currency(void)
{
static char currency[4];
static gboolean got_it = FALSE;
struct lconv *lc;
int i;
if (got_it)
return currency;
for (i = 0; i < 4; i++)
currency[i] = 0;
lc = gnc_localeconv();
strncpy(currency, lc->int_curr_symbol, 3);
got_it = TRUE;
gnc_commodity *
gnc_locale_default_currency(void) {
static gnc_commodity * currency;
struct lconv * lc;
static gboolean got_it = FALSE;
if(got_it == FALSE) {
lc = gnc_localeconv();
currency = gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
lc->int_curr_symbol);
got_it = TRUE;
}
return currency;
}
@ -653,7 +647,7 @@ PrintAmt(char *buf, double val, int prec,
}
int
xaccSPrintAmountGeneral (char * bufp, double val,
DxaccSPrintAmountGeneral (char * bufp, double val,
GNCPrintAmountFlags flags,
int precision,
int min_trailing_zeros,
@ -788,8 +782,8 @@ xaccSPrintAmountGeneral (char * bufp, double val,
}
int
xaccSPrintAmount (char * bufp, double val, GNCPrintAmountFlags flags,
const char *curr_code)
DxaccSPrintAmount (char * bufp, double val, GNCPrintAmountFlags flags,
const char * curr_code)
{
struct lconv *lc;
int precision;
@ -832,24 +826,24 @@ xaccSPrintAmount (char * bufp, double val, GNCPrintAmountFlags flags,
min_trailing_zeros = lc->frac_digits;
}
return xaccSPrintAmountGeneral(bufp, val, flags, precision,
return DxaccSPrintAmountGeneral(bufp, val, flags, precision,
min_trailing_zeros, curr_code);
}
const char *
xaccPrintAmount (double val, GNCPrintAmountFlags flags, const char *curr_code)
DxaccPrintAmount (double val, GNCPrintAmountFlags flags, const char *curr_code)
{
/* hack alert -- this is not thread safe ... */
static char buf[BUFSIZE];
xaccSPrintAmount (buf, val, flags, curr_code);
DxaccSPrintAmount (buf, val, flags, curr_code);
/* its OK to return buf, since we declared it static */
return buf;
}
const char *
xaccPrintAmountArgs (double val, gboolean print_currency_symbol,
DxaccPrintAmountArgs (double val, gboolean print_currency_symbol,
gboolean print_separators, gboolean is_shares_value,
const char *curr_code)
{
@ -859,12 +853,12 @@ xaccPrintAmountArgs (double val, gboolean print_currency_symbol,
if (print_separators) flags |= PRTSEP;
if (is_shares_value) flags |= PRTSHR;
return xaccPrintAmount(val, flags, curr_code);
return DxaccPrintAmount(val, flags, curr_code);
}
/********************************************************************\
* xaccParseAmount *
* DxaccParseAmount *
* parses amount strings using locale data *
* *
* Args: in_str -- pointer to string rep of num *
@ -924,14 +918,14 @@ fractional_multiplier (int num_decimals)
}
gboolean
xaccParseAmount (const char * in_str, gboolean monetary, double *result,
DxaccParseAmount (const char * in_str, gboolean monetary, double *result,
char **endstr)
{
struct lconv *lc = gnc_localeconv();
gboolean is_negative;
gboolean got_decimal;
GList *group_data;
int group_count;
GList * group_data;
int group_count;
double value;
ParseState state;
@ -1092,7 +1086,6 @@ xaccParseAmount (const char * in_str, gboolean monetary, double *result,
else
next_state = NO_NUM_ST;
}
break;
/* IN_GROUP_ST means we are in the middle of parsing

View File

@ -36,6 +36,8 @@
#include <stdlib.h>
#include "gnc-common.h"
#include "gnc-commodity.h"
#include "gnc-numeric.h"
#define BUFSIZE 1024
@ -199,12 +201,9 @@ gboolean gnc_strisnum(const char *s);
*/
struct lconv * gnc_localeconv(void);
/* Returns the 3 character currency code of the current locale. */
const char * gnc_locale_default_currency(void);
/* Return the number of decimal places for this locale. */
int gnc_locale_decimal_places( void );
/* Returns the default currency of the current locale. */
gnc_commodity * gnc_locale_default_currency(void);
int gnc_locale_decimal_places(void);
/*
* The xaccPrintAmount() and xaccSPrintAmount() routines provide
@ -251,22 +250,37 @@ int gnc_locale_decimal_places( void );
typedef unsigned int GNCPrintAmountFlags;
const char * xaccPrintAmount (double val, GNCPrintAmountFlags flags,
const char * DxaccPrintAmount (double val, GNCPrintAmountFlags flags,
const char *curr_code);
int DxaccSPrintAmount (char *buf, double val, GNCPrintAmountFlags flags,
const char * curr_code);
int DxaccSPrintAmountGeneral (char * bufp, double val,
GNCPrintAmountFlags flags,
int precision,
int min_trailing_zeros,
const char *curr_sym);
const char * DxaccPrintAmountArgs (double val,
gboolean print_currency_symbol,
gboolean print_separators,
gboolean is_shares_value,
const char *curr_code);
const char * xaccPrintAmount (gnc_numeric val, GNCPrintAmountFlags flags,
const char *curr_code);
int xaccSPrintAmount (char *buf, double val, GNCPrintAmountFlags flags,
const char *curr_code);
int xaccSPrintAmountGeneral (char * bufp, double val,
int xaccSPrintAmount (char *buf, gnc_numeric val, GNCPrintAmountFlags flags,
const char * curr_code);
int xaccSPrintAmountGeneral (char * bufp, gnc_numeric val,
GNCPrintAmountFlags flags,
int precision,
int min_trailing_zeros,
const char *curr_sym);
const char * xaccPrintAmountArgs (double val,
const char * xaccPrintAmountArgs (gnc_numeric val,
gboolean print_currency_symbol,
gboolean print_separators,
gboolean is_shares_value,
const char *curr_code);
/* xaccParseAmount parses in_str to obtain a numeric result. The
* routine will parse as much of in_str as it can to obtain a single
* number. The number is parsed using the current locale information
@ -279,7 +293,7 @@ const char * xaccPrintAmountArgs (double val,
* parser will be returned in *endstr. If FALSE is returned
* and endstr is non-NULL, *endstr will point to in_str.
*/
gboolean xaccParseAmount (const char * in_str, gboolean monetary,
gboolean DxaccParseAmount (const char * in_str, gboolean monetary,
double *result, char **endstr);

View File

@ -298,7 +298,7 @@ trans_numeric(const char *digit_str,
if (digit_str == NULL)
return NULL;
if (!xaccParseAmount (digit_str, TRUE, &value, rstr))
if (!DxaccParseAmount (digit_str, TRUE, &value, rstr))
return NULL;
pnum = g_new0(ParserNum, 1);

View File

@ -7,16 +7,18 @@ libgncgnome_a_SOURCES = \
dialog-account.c \
dialog-account-picker.c \
dialog-budget.c \
dialog-commodity.c \
dialog-filebox.c \
dialog-fincalc.c \
dialog-find-transactions.c \
dialog-options.c \
dialog-print-check.c \
dialog-progress.c \
dialog-qif-import.c \
dialog-totd.c \
dialog-transfer.c \
dialog-utils.c \
druid-commodity.c \
druid-qif-import.c \
extensions.c \
file-history.c \
glade-gnc-dialogs.c \
@ -34,7 +36,7 @@ libgncgnome_a_SOURCES = \
window-main.c \
window-reconcile.c \
window-register.c \
window-report.c
window-report.c
gnomeappdir = ${datadir}/gnome/apps/Applications
@ -46,15 +48,17 @@ noinst_HEADERS = \
dialog-account.h \
dialog-account-picker.h \
dialog-budget.h \
dialog-commodity.h \
dialog-fincalc.h \
dialog-find-transactions.h \
dialog-options.h \
dialog-print-check.h \
dialog-progress.h \
dialog-qif-import.h \
dialog-totd.h \
dialog-transfer.h \
dialog-utils.h \
druid-commodity.h \
druid-qif-import.h \
extensions.h \
glade-cb-gnc-dialogs.h \
glade-gnc-dialogs.h \

View File

@ -969,11 +969,15 @@ gnc_account_tree_insert_row(GNCAccountTree *tree,
if (acc == NULL)
return NULL;
for (i = 0; i < tree->num_columns; i++)
{
for (i = 0; i < tree->num_columns; i++) {
text[i] =
g_strdup(gnc_ui_get_account_field_value_string(acc,
tree->column_fields[i]));
/* Since string fields like notes can be NULL */
if(!text[i]) {
text[i] = g_strdup("");
}
}
text[tree->num_columns] = NULL;

View File

@ -34,9 +34,10 @@
#include "Refresh.h"
#include "window-main.h"
#include "dialog-utils.h"
#include "dialog-commodity.h"
#include "account-tree.h"
#include "global-options.h"
#include "gnc-currency-edit.h"
#include "gnc-commodity.h"
#include "glade-gnc-dialogs.h"
#include "ui-callbacks.h"
#include "window-help.h"
@ -68,13 +69,15 @@ struct _AccountWindow
GtkWidget * code_entry;
GtkWidget * notes_text;
GtkWidget * currency_picker;
GtkWidget * security_picker;
GtkWidget * currency_entry;
const gnc_commodity * selected_currency;
GtkWidget * security_entry;
GtkWidget * security_button;
const gnc_commodity * selected_security;
GtkWidget * type_list;
GtkWidget * parent_tree;
GtkWidget * source_menu;
gint source;
@ -95,15 +98,13 @@ static gboolean default_currency_dynamically_allocated = FALSE;
static GList *new_account_windows = NULL;
static AccountWindow ** editAccountList = NULL;
/** Implementation *******************************************************/
/* Copy the account values to the GUI widgets */
static void
gnc_account_to_ui(AccountWindow *aw)
{
AccInfo *accinfo;
InvAcct *invacct;
const gnc_commodity * commodity=NULL;
const char *string;
gint pos = 0;
@ -113,19 +114,32 @@ gnc_account_to_ui(AccountWindow *aw)
string = xaccAccountGetDescription (aw->account);
gtk_entry_set_text(GTK_ENTRY(aw->description_entry), string);
string = xaccAccountGetCurrency (aw->account);
gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT (aw->currency_picker),
string);
string = xaccAccountGetSecurity (aw->account);
gtk_entry_set_text(GTK_ENTRY(aw->security_picker), string);
commodity = xaccAccountGetCurrency (aw->account);
if(commodity) {
gtk_entry_set_text(GTK_ENTRY(aw->currency_entry),
gnc_commodity_get_printname(commodity));
}
else {
gtk_entry_set_text(GTK_ENTRY(aw->currency_entry), "");
}
aw->selected_currency = commodity;
commodity = xaccAccountGetSecurity (aw->account);
if(commodity) {
gtk_entry_set_text(GTK_ENTRY(aw->security_entry),
gnc_commodity_get_printname(commodity));
}
else {
gtk_entry_set_text(GTK_ENTRY(aw->security_entry), "");
}
aw->selected_security = commodity;
string = xaccAccountGetCode (aw->account);
gtk_entry_set_text(GTK_ENTRY(aw->code_entry), string);
string = xaccAccountGetNotes (aw->account);
if (string == NULL)
string = "";
if (string == NULL) string = "";
gtk_editable_delete_text (GTK_EDITABLE (aw->notes_text), 0, -1);
gtk_editable_insert_text (GTK_EDITABLE (aw->notes_text), string,
strlen(string), &pos);
@ -133,15 +147,14 @@ gnc_account_to_ui(AccountWindow *aw)
if ((STOCK != aw->type) && (MUTUAL != aw->type) && (CURRENCY != aw->type))
return;
accinfo = xaccAccountGetAccInfo(aw->account);
invacct = xaccCastToInvAcct(accinfo);
if (invacct == NULL)
return;
string = xaccInvAcctGetPriceSrc(invacct);
gtk_option_menu_set_history(GTK_OPTION_MENU(aw->source_menu),
gnc_get_source_code(string));
{
/* we'll let GetPriceSrc handle the account type checking... */
const char* price_src = xaccAccountGetPriceSrc(aw->account);
if (price_src) {
gtk_option_menu_set_history(GTK_OPTION_MENU(aw->source_menu),
gnc_get_source_code(price_src));
}
}
}
@ -150,11 +163,10 @@ static void
gnc_ui_to_account(AccountWindow *aw)
{
Account *parent_account;
GtkEntry *entry;
const char *old_string;
const char *string;
xaccAccountBeginEdit (aw->account, TRUE);
xaccAccountBeginEdit (aw->account);
if (aw->type != xaccAccountGetType (aw->account))
xaccAccountSetType (aw->account, aw->type);
@ -169,38 +181,33 @@ gnc_ui_to_account(AccountWindow *aw)
if (safe_strcmp (string, old_string) != 0)
xaccAccountSetDescription (aw->account, string);
entry = GTK_ENTRY(GTK_COMBO(aw->currency_picker)->entry);
string = gtk_entry_get_text(entry);
old_string = xaccAccountGetCurrency (aw->account);
if (safe_strcmp (string, old_string) != 0)
xaccAccountSetCurrency (aw->account, string);
if (aw->selected_currency &&
!gnc_commodity_equiv(aw->selected_currency,
xaccAccountGetCurrency(aw->account))) {
xaccAccountSetCurrency (aw->account, aw->selected_currency);
}
string = gtk_entry_get_text (GTK_ENTRY(aw->code_entry));
old_string = xaccAccountGetCode (aw->account);
if (safe_strcmp (string, old_string) != 0)
xaccAccountSetCode (aw->account, string);
if ((STOCK == aw->type) || (MUTUAL == aw->type) || (CURRENCY == aw->type))
{
AccInfo *accinfo;
InvAcct *invacct;
if ((STOCK == aw->type) || (MUTUAL == aw->type) || (CURRENCY == aw->type)) {
string = gtk_entry_get_text(GTK_ENTRY(aw->security_picker));
old_string = xaccAccountGetSecurity (aw->account);
if (safe_strcmp (string, old_string) != 0)
xaccAccountSetSecurity (aw->account, string);
if (aw->selected_security &&
!gnc_commodity_equiv(aw->selected_security,
xaccAccountGetSecurity(aw->account))) {
xaccAccountSetSecurity (aw->account, aw->selected_security);
}
accinfo = xaccAccountGetAccInfo(aw->account);
invacct = xaccCastToInvAcct(accinfo);
if (invacct != NULL)
{
if((STOCK == aw->type) || (MUTUAL == aw->type)) {
gint code;
code = gnc_option_menu_get_active (aw->source_menu);
string = gnc_get_source_code_name (code);
old_string = xaccInvAcctGetPriceSrc (invacct);
old_string = xaccAccountGetPriceSrc (aw->account);
if (safe_strcmp (string, old_string) != 0)
xaccInvAcctSetPriceSrc(invacct, string);
xaccAccountSetPriceSrc(aw->account, string);
}
}
@ -214,7 +221,7 @@ gnc_ui_to_account(AccountWindow *aw)
if (parent_account == aw->top_level_account)
parent_account = NULL;
xaccAccountBeginEdit (parent_account, TRUE);
xaccAccountBeginEdit (parent_account);
if (parent_account != NULL)
{
@ -288,22 +295,22 @@ change_func(gpointer key, gpointer value, gpointer field_code)
if (account == NULL)
return;
xaccAccountBeginEdit(account, TRUE);
xaccAccountBeginEdit(account);
switch (field)
{
case ACCOUNT_CURRENCY:
{
char * string = value;
gnc_commodity * currency = value;
xaccAccountSetCurrency(account, string);
xaccAccountSetCurrency(account, currency);
}
break;
case ACCOUNT_SECURITY:
{
char * string = value;
gnc_commodity * security = value;
xaccAccountSetSecurity(account, string);
xaccAccountSetSecurity(account, security);
}
break;
case ACCOUNT_TYPE:
@ -357,11 +364,11 @@ static void
gnc_account_change_currency_security(Account *account,
GHashTable *change_currency,
GHashTable *change_security,
const char *currency,
const char *security)
const gnc_commodity * currency,
const gnc_commodity * security)
{
const char *old_currency;
const char *old_security;
const gnc_commodity * old_currency;
const gnc_commodity * old_security;
gboolean new_currency;
gboolean new_security;
GSList *stack;
@ -372,21 +379,22 @@ gnc_account_change_currency_security(Account *account,
old_currency = xaccAccountGetCurrency(account);
old_security = xaccAccountGetSecurity(account);
if ((safe_strcmp(currency, old_currency) == 0) &&
(safe_strcmp(security, old_security) == 0))
if ((gnc_commodity_equiv(currency, old_currency)) &&
(gnc_commodity_equiv(security, old_security))) {
return;
}
if (safe_strcmp(currency, old_currency) != 0)
if (!gnc_commodity_equiv(currency, old_currency))
{
g_hash_table_insert(change_currency, account, (char *) currency);
g_hash_table_insert(change_currency, account, (gpointer) currency);
new_currency = TRUE;
}
else
new_currency = FALSE;
if (safe_strcmp(security, old_security) != 0)
if (gnc_commodity_equiv(security, old_security))
{
g_hash_table_insert(change_security, account, (char *) security);
g_hash_table_insert(change_security, account, (gpointer) security);
new_security = TRUE;
}
else
@ -426,8 +434,8 @@ gnc_account_change_currency_security(Account *account,
while ((s = xaccTransGetSplit(trans, j++)) != NULL)
{
gboolean add_it = FALSE;
const char *commodity;
Account *a;
const gnc_commodity * commodity;
Account * a;
a = xaccSplitGetAccount(s);
@ -442,13 +450,13 @@ gnc_account_change_currency_security(Account *account,
commodity = xaccAccountGetCurrency(a);
if (new_currency && (safe_strcmp(old_currency, commodity) == 0))
if (new_currency && (gnc_commodity_equiv(old_currency, commodity)))
{
g_hash_table_insert(change_currency, a, (gpointer) currency);
add_it = TRUE;
}
if (new_security && (safe_strcmp(old_security, commodity) == 0))
if (new_security && (gnc_commodity_equiv(old_security, commodity)))
{
g_hash_table_insert(change_currency, a, (gpointer) security);
add_it = TRUE;
@ -456,13 +464,13 @@ gnc_account_change_currency_security(Account *account,
commodity = xaccAccountGetSecurity(a);
if (new_security && (safe_strcmp(old_security, commodity) == 0))
if (new_security && (gnc_commodity_equiv(old_security, commodity)))
{
g_hash_table_insert(change_security, a, (gpointer) security);
add_it = TRUE;
}
if (new_currency && (safe_strcmp(old_currency, commodity) == 0))
if (new_currency && (gnc_commodity_equiv(old_currency, commodity)))
{
g_hash_table_insert(change_security, a, (gpointer) currency);
add_it = TRUE;
@ -488,37 +496,59 @@ fill_helper(gpointer key, gpointer value, gpointer data)
{
Account *account = key;
FillStruct *fs = data;
gchar *strings[5];
if (fs == NULL)
return;
if (fs->account == account)
return;
strings[0] = xaccAccountGetFullName(account, gnc_get_account_separator());
strings[1] = (gchar *) gnc_ui_get_account_field_name(fs->field);
strings[2] = (gchar *) gnc_ui_get_account_field_value_string(account,
fs->field);
strings[4] = NULL;
switch (fs->field)
{
case ACCOUNT_CURRENCY:
case ACCOUNT_SECURITY:
strings[3] = value;
break;
case ACCOUNT_TYPE:
strings[3] = xaccAccountGetTypeStr(GPOINTER_TO_INT(value));
break;
default:
g_warning("unexpected field type");
free(strings[0]);
return;
gchar *full_name;
gchar *account_field_name;
gchar *account_field_value;
gchar *value_str;
if(fs == NULL) return;
if(fs->account == account) return;
full_name = xaccAccountGetFullName(account, gnc_get_account_separator());
if(!full_name) {
full_name = g_strdup("");
} else {
/* Make sure this was allocated with glib funcs */
gchar *tmp = full_name;
full_name = g_strdup(tmp);
free(tmp);
}
gtk_clist_append(fs->list, strings);
free(strings[0]);
account_field_name = g_strdup(gnc_ui_get_account_field_name(fs->field));
if(!account_field_name) account_field_name = g_strdup("");
account_field_value =
g_strdup(gnc_ui_get_account_field_value_string(account, fs->field));
if(!account_field_value) account_field_value = g_strdup("");
switch (fs->field) {
case ACCOUNT_CURRENCY:
case ACCOUNT_SECURITY:
value_str = g_strdup(gnc_commodity_get_printname(value));
break;
case ACCOUNT_TYPE:
value_str = g_strdup(xaccAccountGetTypeStr(GPOINTER_TO_INT(value)));
break;
default:
g_warning("unexpected field type");
g_free(full_name);
g_free(account_field_name);
g_free(account_field_value);
return;
}
{
gchar *strings[5];
strings[0] = full_name;
strings[1] = account_field_name;
strings[2] = account_field_value;
strings[3] = value_str;
strings[4] = NULL;
gtk_clist_append(fs->list, strings);
}
g_free(full_name);
g_free(account_field_name);
g_free(account_field_value);
g_free(value_str);
fs->count++;
}
@ -672,8 +702,8 @@ gnc_edit_account_ok(AccountWindow *aw)
GNCAccountType current_type;
const char *name;
const char *currency;
const char *security;
const gnc_commodity * currency;
const gnc_commodity * security;
/* check for valid name */
name = gtk_entry_get_text(GTK_ENTRY(aw->name_entry));
@ -709,9 +739,8 @@ gnc_edit_account_ok(AccountWindow *aw)
change_security = g_hash_table_new(NULL, NULL);
change_type = g_hash_table_new(NULL, NULL);
currency =
gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(aw->currency_picker)->entry));
security = gtk_entry_get_text(GTK_ENTRY(aw->security_picker));
currency = aw->selected_currency;
security = aw->selected_security;
gnc_account_change_currency_security(account,
change_currency,
@ -861,6 +890,48 @@ gnc_new_account_ok (AccountWindow *aw)
}
/*************************************************************
* currecy/security selector callbacks
*************************************************************/
void
gnc_account_window_select_currency_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = user_data;
AccountWindow * aw =
gtk_object_get_data(GTK_OBJECT(dialog), "account_window_struct");
const gnc_commodity * new_currency =
gnc_ui_select_commodity_modal(aw->selected_currency, NULL);
/* NULL return means cancel; no change */
if(new_currency) {
aw->selected_currency = new_currency;
gtk_entry_set_text(GTK_ENTRY(aw->currency_entry),
gnc_commodity_get_printname(new_currency));
}
}
void
gnc_account_window_select_security_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = user_data;
AccountWindow * aw =
gtk_object_get_data(GTK_OBJECT(dialog), "account_window_struct");
const gnc_commodity * new_security =
gnc_ui_select_commodity_modal(aw->selected_security, NULL);
if(new_security) {
aw->selected_security = new_security;
gtk_entry_set_text(GTK_ENTRY(aw->security_entry),
gnc_commodity_get_printname(new_security));
}
}
static void
gnc_account_window_ok_cb(GtkWidget * widget, gpointer data)
{
@ -978,7 +1049,7 @@ gnc_type_list_select_cb(GtkCList * type_list, gint row, gint column,
aw->type == MUTUAL ||
aw->type == CURRENCY);
gtk_widget_set_sensitive(aw->security_picker, sensitive);
gtk_widget_set_sensitive(aw->security_button, sensitive);
gtk_widget_set_sensitive(aw->source_menu, sensitive);
}
@ -991,7 +1062,7 @@ gnc_type_list_unselect_cb(GtkCList * type_list, gint row, gint column,
aw->type = BAD_TYPE;
gtk_widget_set_sensitive(aw->security_picker, FALSE);
gtk_widget_set_sensitive(aw->security_button, FALSE);
gtk_widget_set_sensitive(aw->source_menu, FALSE);
}
@ -1134,17 +1205,19 @@ gnc_account_window_create(AccountWindow *aw)
aw->description_entry = gtk_object_get_data(awo, "description_entry");
aw->code_entry = gtk_object_get_data(awo, "code_entry");
aw->notes_text = gtk_object_get_data(awo, "notes_text");
aw->currency_entry = gtk_object_get_data(awo, "currency_entry");
aw->security_entry = gtk_object_get_data(awo, "security_entry");
aw->security_button = gtk_object_get_data(awo, "security_button");
aw->selected_currency = NULL;
aw->selected_security = NULL;
gtk_object_set_data(awo, "account_window_struct", aw);
gnome_dialog_editable_enters(awd, GTK_EDITABLE(aw->name_entry));
gnome_dialog_editable_enters(awd, GTK_EDITABLE(aw->description_entry));
gnome_dialog_editable_enters(awd, GTK_EDITABLE(aw->code_entry));
box = gtk_object_get_data(awo, "currency_box");
aw->currency_picker = gnc_currency_edit_new();
gtk_box_pack_start(GTK_BOX(box), aw->currency_picker, TRUE, TRUE, 0);
aw->security_picker = gtk_object_get_data(awo, "security_entry");
box = gtk_object_get_data(awo, "source_box");
aw->source_menu = gnc_ui_source_menu_create(aw->account);
gtk_box_pack_start(GTK_BOX(box), aw->source_menu, TRUE, TRUE, 0);
@ -1153,8 +1226,10 @@ gnc_account_window_create(AccountWindow *aw)
gnc_account_type_list_create (aw);
box = gtk_object_get_data(awo, "parent_scroll");
aw->top_level_account = xaccMallocAccount();
xaccAccountSetName(aw->top_level_account, NEW_TOP_ACCT_STR);
aw->parent_tree = gnc_account_tree_new_with_root(aw->top_level_account);
gtk_clist_column_titles_hide(GTK_CLIST(aw->parent_tree));
gnc_account_tree_hide_all_but_name(GNC_ACCOUNT_TREE(aw->parent_tree));
@ -1199,10 +1274,15 @@ gnc_ui_new_account_window (AccountGroup *this_is_not_used)
gnc_account_window_create(aw);
new_account_windows = g_list_prepend(new_account_windows, aw->dialog);
gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(aw->currency_picker),
default_currency);
aw->selected_currency =
gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
default_currency);
gtk_entry_set_text(GTK_ENTRY(aw->currency_entry),
gnc_commodity_get_printname(aw->selected_currency));
gtk_widget_show_all(aw->dialog);
parent = gnc_get_current_account();

View File

@ -340,6 +340,7 @@ static void
load_subentry(BudgetDialog *bd)
{
char *string;
const char *const_string;
SCM subentry;
subentry = bd->current_subentry;
@ -361,8 +362,8 @@ load_subentry(BudgetDialog *bd)
value = gh_call1(getters.subentry_amount, subentry);
amount = gh_scm2double(value);
string = xaccPrintAmount(amount, PRTSEP, NULL);
gtk_entry_set_text(GTK_ENTRY(bd->subentry_amount_entry), string);
const_string = DxaccPrintAmount(amount, PRTSEP, NULL);
gtk_entry_set_text(GTK_ENTRY(bd->subentry_amount_entry), const_string);
value = gh_call1(getters.subentry_period, subentry);
period = gh_scm2int(value);
@ -855,7 +856,7 @@ subentry_amount_entry_focus_out(GtkWidget *widget, GdkEventFocus *event,
BudgetDialog *bd)
{
GtkEntry *entry = GTK_ENTRY(widget);
gchar *new_string;
const gchar *new_string;
gchar *string;
double value;
@ -865,9 +866,9 @@ subentry_amount_entry_focus_out(GtkWidget *widget, GdkEventFocus *event,
return FALSE;
value = 0.0;
xaccParseAmount(string, TRUE, &value, NULL);
DxaccParseAmount(string, TRUE, &value, NULL);
new_string = xaccPrintAmount(value, PRTSEP, NULL);
new_string = DxaccPrintAmount(value, PRTSEP, NULL);
if (safe_strcmp(string, new_string) == 0)
return FALSE;

View File

@ -0,0 +1,499 @@
/********************************************************************
* dialog-commodity.c -- "select" and "new" commodity windows *
* (GnuCash) *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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 <gtk/gtk.h>
#include <glib.h>
#include <stdio.h>
#include "dialog-commodity.h"
#include "window-help.h"
#include "FileDialog.h"
#include "query-user.h"
struct _selectcommoditywindow {
GtkWidget * dialog;
GtkWidget * namespace_combo;
GtkWidget * namespace_entry;
GtkWidget * commodity_combo;
GtkWidget * commodity_entry;
gnc_commodity_callback callback;
void * callback_data;
};
struct _newcommoditywindow {
GtkWidget * dialog;
GtkWidget * fullname_entry;
GtkWidget * mnemonic_entry;
GtkWidget * namespace_entry;
GtkWidget * namespace_combo;
GtkWidget * code_entry;
GtkWidget * fraction_spinbutton;
gnc_commodity_callback callback;
void * callback_data;
};
static void
select_modal_callback(const gnc_commodity * arg, void * data) {
*((const gnc_commodity **)data) = arg;
}
/********************************************************************
* gnc_ui_select_commodity_modal()
********************************************************************/
const gnc_commodity *
gnc_ui_select_commodity_modal(const gnc_commodity * orig_sel,
GtkWidget * parent) {
const gnc_commodity * retval = NULL;
SelectCommodityWindow * win =
gnc_ui_select_commodity_create(orig_sel, &select_modal_callback, &retval);
if(parent) {
gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent));
}
gtk_window_set_modal(GTK_WINDOW(win->dialog), TRUE);
gtk_main();
return retval;
}
static gint
select_commodity_close (GnomeDialog *dialog, gpointer data)
{
SelectCommodityWindow *scw = data;
g_free(scw);
return FALSE;
}
/********************************************************************
* gnc_ui_select_commodity_create()
********************************************************************/
SelectCommodityWindow *
gnc_ui_select_commodity_create(const gnc_commodity * orig_sel,
gnc_commodity_callback callback,
void * callback_data) {
SelectCommodityWindow * retval = g_new0(SelectCommodityWindow, 1);
char * namespace;
retval->dialog = create_Commodity_Selector_Dialog();
retval->namespace_combo =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "namespace_combo");
retval->namespace_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "namespace_entry");
retval->commodity_combo =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "commodity_combo");
retval->commodity_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "commodity_entry");
retval->callback = callback;
retval->callback_data = callback_data;
gtk_signal_connect (GTK_OBJECT(retval->dialog), "close",
GTK_SIGNAL_FUNC(select_commodity_close), retval);
gtk_object_set_data(GTK_OBJECT(retval->dialog), "select_commodity_struct",
retval);
/* build the menus of namespaces and commodities */
namespace =
gnc_ui_update_namespace_picker(retval->namespace_combo,
gnc_commodity_get_namespace(orig_sel));
gnc_ui_update_commodity_picker(retval->commodity_combo, namespace,
gnc_commodity_get_printname(orig_sel));
gtk_widget_show_all(retval->dialog);
g_free(namespace);
return retval;
}
/********************************************************************
* gnc_ui_update_commodity_picker
********************************************************************/
static int
g_strcmp(gconstpointer a, gconstpointer b) {
return strcmp(a, b);
}
void
gnc_ui_update_commodity_picker(GtkWidget * combobox,
const char * namespace,
const char * init_string) {
GList * commodities =
gnc_commodity_table_get_commodities(gnc_engine_commodities(),
namespace);
GList * iterator = NULL;
GList * commodity_items = NULL;
const char * current;
for(iterator = commodities; iterator; iterator = iterator->next) {
commodity_items =
g_list_append(commodity_items,
(gpointer) gnc_commodity_get_printname(iterator->data));
}
commodity_items = g_list_sort(commodity_items, g_strcmp);
if(!commodity_items) {
commodity_items = g_list_append(commodity_items, "");
}
gtk_combo_set_popdown_strings(GTK_COMBO(combobox),
commodity_items);
if(init_string) {
current = init_string;
}
else {
current = commodity_items->data;
}
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combobox)->entry), current);
/* free the lists */
g_list_free(commodities);
g_list_free(commodity_items);
}
/********************************************************************
* gnc_ui_select_commodity_destroy()
********************************************************************/
void
gnc_ui_select_commodity_destroy(SelectCommodityWindow * w) {
if(w) {
gtk_main_quit();
gnome_dialog_close(GNOME_DIALOG(w->dialog));
}
}
/********************************************************************
* gnc_ui_select_commodity_ok_cb()
********************************************************************/
void
gnc_ui_select_commodity_ok_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
SelectCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "select_commodity_struct");
char * namespace;
char * fullname;
gnc_commodity * retval = NULL;
namespace = gtk_entry_get_text(GTK_ENTRY(w->namespace_entry));
fullname = gtk_entry_get_text(GTK_ENTRY(w->commodity_entry));
retval = gnc_commodity_table_find_full(gnc_engine_commodities(),
namespace,
fullname);
if(retval) {
if (w->callback)
(w->callback)(retval, w->callback_data);
gnc_ui_select_commodity_destroy(w);
}
else {
gnc_warning_dialog(_("You must select a commodity.\n"
"To create a new one, click \"New\""));
}
}
/********************************************************************
* gnc_ui_select_commodity_new_cb()
********************************************************************/
void
gnc_ui_select_commodity_new_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
SelectCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "select_commodity_struct");
char * namespace =
gtk_entry_get_text(GTK_ENTRY(w->namespace_entry));
const gnc_commodity * new_commodity =
gnc_ui_new_commodity_modal(namespace, dialog);
if(new_commodity) {
char *namespace;
namespace =
gnc_ui_update_namespace_picker(w->namespace_combo,
gnc_commodity_get_namespace
(new_commodity));
g_free(namespace);
gnc_ui_update_commodity_picker(w->commodity_combo,
gnc_commodity_get_namespace(new_commodity),
gnc_commodity_get_printname(new_commodity));
}
}
/********************************************************************
* gnc_ui_select_commodity_cancel_cb()
********************************************************************/
void
gnc_ui_select_commodity_cancel_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
SelectCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "select_commodity_struct");
if (w->callback)
(w->callback)(NULL, w->callback_data);
gnc_ui_select_commodity_destroy(w);
}
/********************************************************************
* gnc_ui_select_commodity_namespace_changed_cb()
********************************************************************/
void
gnc_ui_select_commodity_namespace_changed_cb(GtkEditable * entry,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
SelectCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "select_commodity_struct");
char * namespace =
gtk_entry_get_text(GTK_ENTRY(w->namespace_entry));
gnc_ui_update_commodity_picker(w->commodity_combo,
namespace, NULL);
}
/********************************************************************
* gnc_ui_update_namespace_picker
********************************************************************/
char *
gnc_ui_update_namespace_picker(GtkWidget * combobox,
const char * init_string) {
GList * namespaces;
char * active;
/* fetch a list of the namespaces */
namespaces = gnc_commodity_table_get_namespaces(gnc_engine_commodities());
namespaces = g_list_sort(namespaces, g_strcmp);
/* stick them in the combobox */
gtk_combo_set_popdown_strings(GTK_COMBO(combobox), namespaces);
/* set the entry text */
if(init_string) {
active = g_strdup(init_string);
}
else {
active = g_strdup(namespaces->data);
}
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combobox)->entry), active);
g_list_free(namespaces);
return active;
}
static gint
new_commodity_close (GnomeDialog *dialog, gpointer data)
{
NewCommodityWindow *ncw = data;
g_free(ncw);
return FALSE;
}
/********************************************************************
* gnc_ui_new_commodity_create()
********************************************************************/
NewCommodityWindow *
gnc_ui_new_commodity_create(const char * selected_namespace,
gnc_commodity_callback callback,
void * callback_data) {
NewCommodityWindow * retval = g_new0(NewCommodityWindow, 1);
char *namespace;
retval->dialog = create_New_Commodity_Dialog();
retval->fullname_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "fullname_entry");
retval->mnemonic_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "mnemonic_entry");
retval->namespace_combo =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "namespace_combo");
retval->namespace_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "namespace_entry");
retval->code_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "code_entry");
retval->fraction_spinbutton =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "fraction_spinbutton");
retval->callback = callback;
retval->callback_data = callback_data;
gtk_object_set_data(GTK_OBJECT(retval->dialog), "new_commodity_struct",
(gpointer)retval);
gtk_signal_connect (GTK_OBJECT(retval->dialog), "close",
GTK_SIGNAL_FUNC(new_commodity_close), retval);
gtk_widget_show_all(retval->dialog);
namespace = gnc_ui_update_namespace_picker(retval->namespace_combo,
selected_namespace);
g_free(namespace);
return retval;
}
static void
new_modal_callback(const gnc_commodity * arg, void * data) {
*((const gnc_commodity **)data) = arg;
}
/********************************************************************
* gnc_ui_new_commodity_modal()
********************************************************************/
const gnc_commodity *
gnc_ui_new_commodity_modal(const char * selected_namespace,
GtkWidget * parent) {
gnc_commodity * retval = NULL;
NewCommodityWindow * win =
gnc_ui_new_commodity_create(selected_namespace, &new_modal_callback,
&retval);
if(parent) {
gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent));
}
gtk_window_set_modal(GTK_WINDOW(win->dialog), TRUE);
gtk_main();
return retval;
}
/********************************************************************
* gnc_ui_new_commodity_destroy()
********************************************************************/
void
gnc_ui_new_commodity_destroy(NewCommodityWindow * w) {
if(w) {
gtk_main_quit();
gnome_dialog_close(GNOME_DIALOG(w->dialog));
}
}
/********************************************************************
* gnc_ui_new_commodity_ok_cb()
********************************************************************/
void
gnc_ui_new_commodity_ok_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
NewCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "new_commodity_struct");
char * fullname = gtk_entry_get_text(GTK_ENTRY(w->fullname_entry));
char * namespace = gtk_entry_get_text(GTK_ENTRY(w->namespace_entry));
char * mnemonic = gtk_entry_get_text(GTK_ENTRY(w->mnemonic_entry));
gnc_commodity * c;
if(fullname && fullname[0] &&
namespace && namespace[0] &&
mnemonic && mnemonic[0]) {
c = gnc_commodity_new(fullname, namespace, mnemonic,
gtk_entry_get_text
(GTK_ENTRY(w->code_entry)),
gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(w->fraction_spinbutton)));
/* remember the commodity */
gnc_commodity_table_insert(gnc_engine_commodities(), c);
/* if there's a callback (generally to fill in some fields with
* info about the commodity) call it */
if(w->callback) {
(w->callback)(c, w->callback_data);
}
/* close the dialog */
gnc_ui_new_commodity_destroy(w);
}
else {
gnc_warning_dialog(_("You must enter a non-empty \"Full name\", "
"\"Symbol/abbreviation\",\n"
"and \"Type\" for the commodity."));
}
}
/********************************************************************
* gnc_ui_new_commodity_new_cb()
********************************************************************/
void
gnc_ui_new_commodity_help_cb(GtkButton * button,
gpointer user_data) {
/* GtkWidget * dialog = GTK_WIDGET(user_data); */
helpWindow(NULL, _("Help"), HH_COMMODITY);
}
/********************************************************************
* gnc_ui_new_commodity_cancel_cb()
********************************************************************/
void
gnc_ui_new_commodity_cancel_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
NewCommodityWindow * w =
gtk_object_get_data(GTK_OBJECT(dialog), "new_commodity_struct");
if (w->callback) {
(w->callback)(NULL, w->callback_data);
}
gnc_ui_new_commodity_destroy(w);
}

View File

@ -0,0 +1,65 @@
/********************************************************************
* dialog-commodity.h -- "select" and "new" commodity windows *
* (GnuCash) *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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_COMMODITY_H_
#define __DIALOG_COMMODITY_H_
#include "glade-gnc-dialogs.h"
#include "glade-cb-gnc-dialogs.h"
#include "ui-callbacks.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
typedef struct _selectcommoditywindow SelectCommodityWindow;
typedef struct _newcommoditywindow NewCommodityWindow;
typedef void (* gnc_commodity_callback)(const gnc_commodity *, void * data);
SelectCommodityWindow *
gnc_ui_select_commodity_create(const gnc_commodity * orig_sel,
gnc_commodity_callback cb,
void * callback_data);
void gnc_ui_select_commodity_destroy(SelectCommodityWindow * w);
NewCommodityWindow *
gnc_ui_new_commodity_create(const char * selected_namespace,
gnc_commodity_callback cb,
void * callback_data);
void gnc_ui_new_commodity_destroy(NewCommodityWindow * w);
const gnc_commodity *
gnc_ui_select_commodity_modal(const gnc_commodity * orig_sel,
GtkWidget * parent);
const gnc_commodity *
gnc_ui_new_commodity_modal(const char * default_namespace,
GtkWidget * parent);
char * gnc_ui_update_namespace_picker(GtkWidget * combobox, const char * sel);
void gnc_ui_update_commodity_picker(GtkWidget * combobox,
const char * namespace,
const char * sel);
#endif

View File

@ -135,15 +135,13 @@ fi_to_gui(FinCalcDialog *fcd)
gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(fcd->amounts[PRESENT_VALUE]),
fcd->financial_info.pv);
gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(fcd->amounts[PERIODIC_PAYMENT]),
fcd->financial_info.pmt);
gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(fcd->amounts[FUTURE_VALUE]),
-fcd->financial_info.fv);
total = fcd->financial_info.npp * fcd->financial_info.pmt;
xaccSPrintAmount (string, total, PRTSEP, NULL);
DxaccSPrintAmount (string, total, PRTSEP, NULL);
gtk_label_set_text (GTK_LABEL(fcd->payment_total_label), string);
i = normalize_period(&fcd->financial_info.CF);
@ -176,16 +174,13 @@ gui_to_fi(FinCalcDialog *fcd)
string = gtk_entry_get_text(GTK_ENTRY(fcd->amounts[PAYMENT_PERIODS]));
fcd->financial_info.npp = strtol(string, NULL, 10);
fcd->financial_info.ir =
gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(fcd->amounts[INTEREST_RATE]));
fcd->financial_info.pv =
gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(fcd->amounts[PRESENT_VALUE]));
fcd->financial_info.pmt =
gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(fcd->amounts[PERIODIC_PAYMENT]));
fcd->financial_info.fv =
gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(fcd->amounts[FUTURE_VALUE]));
fcd->financial_info.fv = -fcd->financial_info.fv;

View File

@ -43,7 +43,7 @@
#include "dialog-find-transactions.h"
#include "window-help.h"
#include "Query.h"
#include "gnc-dateedit.h"
/********************************************************************\
* gnc_ui_find_transactions_dialog_create
@ -53,7 +53,6 @@
FindTransactionsDialog *
gnc_ui_find_transactions_dialog_create(xaccLedgerDisplay * orig_ledg) {
FindTransactionsDialog * ftd = g_new0(FindTransactionsDialog, 1);
SCM lookup_option, lookup_value;
/* call the glade-defined creator */
ftd->dialog = create_Find_Transactions();
@ -84,18 +83,25 @@ gnc_ui_find_transactions_dialog_create(xaccLedgerDisplay * orig_ledg) {
ftd->match_accounts_picker =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "account_match_picker");
ftd->date_start_entry_1 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_start_entry_1");
ftd->date_start_entry_2 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_start_entry_2");
ftd->date_start_entry_3 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_start_entry_3");
ftd->date_end_entry_1 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_end_entry_1");
ftd->date_end_entry_2 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_end_entry_2");
ftd->date_end_entry_3 =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_end_entry_3");
ftd->date_start_toggle =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_start_toggle");
ftd->date_start_frame =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_start_frame");
ftd->date_start_entry = gnc_date_edit_new(time(NULL), FALSE, FALSE);
gtk_container_add(GTK_CONTAINER(ftd->date_start_frame),
ftd->date_start_entry);
gtk_widget_set_sensitive(ftd->date_start_entry, FALSE);
ftd->date_end_toggle =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_end_toggle");
ftd->date_end_frame =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "date_end_frame");
ftd->date_end_entry = gnc_date_edit_new(time(NULL), FALSE, FALSE);
gtk_container_add(GTK_CONTAINER(ftd->date_end_frame),
ftd->date_end_entry);
gtk_widget_set_sensitive(ftd->date_end_entry, FALSE);
ftd->description_entry =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "description_entry");
@ -149,6 +155,13 @@ gnc_ui_find_transactions_dialog_create(xaccLedgerDisplay * orig_ledg) {
ftd->cleared_not_cleared_toggle =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "cleared_not_cleared_toggle");
ftd->tag_entry =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "tag_entry");
ftd->tag_case_toggle =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "tag_case_toggle");
ftd->tag_regexp_toggle =
gtk_object_get_data(GTK_OBJECT(ftd->dialog), "tag_regexp_toggle");
/* add an account picker to the first tab */
ftd->account_tree = gnc_account_tree_new();
gtk_clist_column_titles_hide(GTK_CLIST(ftd->account_tree));
@ -170,47 +183,6 @@ gnc_ui_find_transactions_dialog_create(xaccLedgerDisplay * orig_ledg) {
gnc_option_menu_init(ftd->shares_comp_picker);
gnc_option_menu_init(ftd->price_comp_picker);
/* initialize the date to something reasonable */
lookup_option = gh_eval_str("gnc:lookup-global-option");
lookup_value = gh_eval_str("gnc:option-value");
ftd->ymd_format =
gh_symbol2newstr(gh_call1(lookup_value,
gh_call2(lookup_option,
gh_str02scm("International"),
gh_str02scm("Date Format"))),
NULL);
if(!strcmp(ftd->ymd_format, "us") ||
!strcmp(ftd->ymd_format, "uk") ||
!strcmp(ftd->ymd_format, "europe")) {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_1),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_2),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_3),
1900.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_1),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_2),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_3),
2100.0);
}
else {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_1),
1900.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_2),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_start_entry_3),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_1),
2100.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_2),
1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ftd->date_end_entry_3),
1.0);
}
/* set data so we can find the struct in callbacks */
gtk_object_set_data(GTK_OBJECT(ftd->dialog), "find_transactions_structure",
ftd);
@ -301,39 +273,43 @@ gnc_ui_find_transactions_dialog_help_cb(GtkButton * button,
/********************************************************************\
* gnc_ui_find_transactions_dialog_early_date_select_cb
* gnc_ui_find_transactions_dialog_early_date_toggle_cb
\********************************************************************/
void
gnc_ui_find_transactions_dialog_early_date_select_cb(GtkButton * button,
gnc_ui_find_transactions_dialog_early_date_toggle_cb(GtkToggleButton * button,
gpointer user_data) {
FindTransactionsDialog * ftd =
gtk_object_get_data(GTK_OBJECT(user_data), "find_transactions_structure");
gnc_ui_select_date_dialog_create(ftd->date_start_entry_1,
ftd->date_start_entry_2,
ftd->date_start_entry_3,
ftd->ymd_format);
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
gtk_widget_set_sensitive(GTK_WIDGET(ftd->date_start_entry), TRUE);
}
else {
gtk_widget_set_sensitive(GTK_WIDGET(ftd->date_start_entry), FALSE);
}
}
/********************************************************************\
* gnc_ui_find_transactions_dialog_late_date_select_cb
* gnc_ui_find_transactions_dialog_late_date_toggle_cb
\********************************************************************/
void
gnc_ui_find_transactions_dialog_late_date_select_cb(GtkButton * button,
gpointer user_data) {
gnc_ui_find_transactions_dialog_late_date_toggle_cb(GtkToggleButton * button,
gpointer user_data) {
FindTransactionsDialog * ftd =
gtk_object_get_data(GTK_OBJECT(user_data), "find_transactions_structure");
gnc_ui_select_date_dialog_create(ftd->date_end_entry_1,
ftd->date_end_entry_2,
ftd->date_end_entry_3,
ftd->ymd_format);
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
gtk_widget_set_sensitive(GTK_WIDGET(ftd->date_end_entry), TRUE);
}
else {
gtk_widget_set_sensitive(GTK_WIDGET(ftd->date_end_entry), FALSE);
}
}
/********************************************************************\
* gnc_ui_find_transactions_dialog_ok_cb
\********************************************************************/
@ -350,6 +326,7 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
char * memo_match_text;
char * number_match_text;
char * action_match_text;
char * tag_match_text;
int search_type = ftd->search_type;
@ -358,8 +335,8 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
Query * q, * q2;
gboolean new_ledger = FALSE;
int start_year, start_month, start_day;
int end_year, end_month, end_day;
int use_start_date, use_end_date;
time_t start_date, end_date;
int c_cleared, c_notcleared, c_reconciled;
@ -394,6 +371,10 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
action_match_text =
gtk_entry_get_text(GTK_ENTRY(ftd->action_entry));
/* tag */
tag_match_text =
gtk_entry_get_text(GTK_ENTRY(ftd->tag_entry));
if(selected_accounts) {
xaccQueryAddAccountMatch(q, selected_accounts,
gnc_option_menu_get_active
@ -432,7 +413,7 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
amt_type = gnc_option_menu_get_active(ftd->credit_debit_picker);
if((amt_temp > 0.00001) || (amt_type != 0)) {
xaccQueryAddAmountMatch(q,
DxaccQueryAddAmountMatch(q,
amt_temp,
amt_type,
gnc_option_menu_get_active
@ -440,74 +421,19 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
QUERY_AND);
}
if(!strcmp(ftd->ymd_format, "us")) {
start_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_1));
start_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_2));
start_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_3));
end_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_1));
end_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_2));
end_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_3));
}
else if(!strcmp(ftd->ymd_format, "uk") ||
!strcmp(ftd->ymd_format, "europe")) {
start_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_1));
start_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_2));
start_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_3));
end_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_1));
end_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_2));
end_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_3));
}
else if(!strcmp(ftd->ymd_format, "iso")) {
start_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_1));
start_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_2));
start_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_3));
end_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_1));
end_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_2));
end_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_3));
}
else {
start_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_1));
start_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_2));
start_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_start_entry_3));
end_day = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_1));
end_month = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_2));
end_year = gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(ftd->date_end_entry_3));
}
if(!((start_day==1) && (start_month==1) && (start_year==1900) &&
(end_day==1) && (end_month==1) && (end_year==2100))) {
xaccQueryAddDateMatch(q,
start_day, start_month, start_year,
end_day, end_month, end_year,
QUERY_AND);
use_start_date =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ftd->date_start_toggle));
use_end_date =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ftd->date_end_toggle));
start_date = gnc_date_edit_get_date(GNC_DATE_EDIT(ftd->date_start_entry));
end_date = gnc_date_edit_get_date(GNC_DATE_EDIT(ftd->date_end_entry));
if(use_start_date || use_end_date) {
xaccQueryAddDateMatchTT(q,
use_start_date, start_date,
use_end_date, end_date,
QUERY_AND);
}
if(strlen(memo_match_text)) {
@ -526,7 +452,7 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
gnc_option_menu_get_active(ftd->price_comp_picker);
if((amt_temp > 0.00001) || (amt_type != 0)) {
xaccQueryAddSharePriceMatch(q,
DxaccQueryAddSharePriceMatch(q,
amt_temp,
amt_type,
QUERY_AND);
@ -539,7 +465,7 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
gnc_option_menu_get_active(ftd->shares_comp_picker);
if((amt_temp > 0.00001) || (amt_type != 0)) {
xaccQueryAddSharesMatch(q,
DxaccQueryAddSharesMatch(q,
amt_temp,
amt_type,
QUERY_AND);
@ -606,147 +532,4 @@ gnc_ui_find_transactions_dialog_ok_cb(GtkButton * button,
gnc_ui_find_transactions_dialog_destroy(ftd);
}
/********************************************************************\
* gnc_ui_select_date_dialog_cancel_cb
\********************************************************************/
SelectDateDialog *
gnc_ui_select_date_dialog_create(GtkWidget * entry_1, GtkWidget * entry_2,
GtkWidget * entry_3, char * ymd_default) {
SelectDateDialog * sdd = g_new0(SelectDateDialog, 1);
int y, m, d;
sdd->dialog = create_Select_Date();
sdd->cal = gtk_object_get_data(GTK_OBJECT(sdd->dialog),
"calendar1");
sdd->entry_1 = entry_1;
sdd->entry_2 = entry_2;
sdd->entry_3 = entry_3;
if(!strcmp(ymd_default, "us")) {
m = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_1));
d = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_2));
y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_3));
}
else if(!strcmp(ymd_default, "uk") ||
!strcmp(ymd_default, "europe")) {
d = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_1));
m = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_2));
y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_3));
}
else if(!strcmp(ymd_default, "iso")) {
y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_1));
m = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_2));
d = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_3));
}
else {
m = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_1));
d = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_2));
y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sdd->entry_3));
}
sdd->ymd_format = strdup(ymd_default);
gtk_calendar_select_month(GTK_CALENDAR(sdd->cal),
m-1, y);
gtk_calendar_select_day(GTK_CALENDAR(sdd->cal),
d);
gtk_object_set_data(GTK_OBJECT(sdd->dialog), "select_date_struct",
sdd);
gtk_widget_show_all(GTK_WIDGET(sdd->dialog));
return sdd;
}
/********************************************************************\
* gnc_ui_select_date_dialog_destroy
\********************************************************************/
void
gnc_ui_select_date_dialog_destroy(SelectDateDialog * sdd) {
gnome_dialog_close(GNOME_DIALOG(sdd->dialog));
g_free(sdd->ymd_format);
g_free(sdd);
}
/********************************************************************\
* gnc_ui_select_date_dialog_cancel_cb
\********************************************************************/
void
gnc_ui_select_date_dialog_cancel_cb(GtkButton * button,
gpointer user_data) {
SelectDateDialog * sdd =
(SelectDateDialog *)gtk_object_get_data(GTK_OBJECT(user_data),
"select_date_struct");
gnc_ui_select_date_dialog_destroy(sdd);
}
/********************************************************************\
* gnc_ui_select_date_dialog_today_cb
\********************************************************************/
void
gnc_ui_select_date_dialog_today_cb(GtkButton * button,
gpointer user_data) {
SelectDateDialog * sdd =
(SelectDateDialog *)gtk_object_get_data(GTK_OBJECT(user_data),
"select_date_struct");
time_t now;
struct tm * bdtime;
now = time(NULL);
bdtime = localtime(&now);
gtk_calendar_select_month(GTK_CALENDAR(sdd->cal),
bdtime->tm_mon,
bdtime->tm_year+1900);
gtk_calendar_select_day(GTK_CALENDAR(sdd->cal),
bdtime->tm_mday);
}
/********************************************************************\
* gnc_ui_select_date_dialog_cancel_cb
\********************************************************************/
void
gnc_ui_select_date_dialog_ok_cb(GtkButton * button,
gpointer user_data) {
SelectDateDialog * sdd =
(SelectDateDialog *)gtk_object_get_data(GTK_OBJECT(user_data),
"select_date_struct");
int y, m, d;
gtk_calendar_get_date(GTK_CALENDAR(sdd->cal), &y, &m, &d);
if(!strcmp(sdd->ymd_format, "us")) {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_1),
(float)m+1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_2),
(float)d);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_3),
(float)y);
}
else if(!strcmp(sdd->ymd_format, "uk") ||
!strcmp(sdd->ymd_format, "europe")) {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_1),
(float)d);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_2),
(float)m+1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_3),
(float)y);
}
else if(!strcmp(sdd->ymd_format, "iso")) {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_1),
(float)y);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_2),
(float)m+1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdd->entry_3),
(float)d);
}
gnc_ui_select_date_dialog_destroy(sdd);
}

View File

@ -62,13 +62,13 @@ typedef struct {
GtkWidget * match_accounts_scroller;
GtkWidget * account_tree;
GtkWidget * date_start_entry_1;
GtkWidget * date_start_entry_2;
GtkWidget * date_start_entry_3;
GtkWidget * date_start_toggle;
GtkWidget * date_start_frame;
GtkWidget * date_start_entry;
GtkWidget * date_end_entry_1;
GtkWidget * date_end_entry_2;
GtkWidget * date_end_entry_3;
GtkWidget * date_end_toggle;
GtkWidget * date_end_frame;
GtkWidget * date_end_entry;
GtkWidget * description_entry;
GtkWidget * description_case_toggle;
@ -100,6 +100,10 @@ typedef struct {
GtkWidget * cleared_cleared_toggle;
GtkWidget * cleared_reconciled_toggle;
GtkWidget * tag_entry;
GtkWidget * tag_case_toggle;
GtkWidget * tag_regexp_toggle;
} FindTransactionsDialog;
FindTransactionsDialog *

View File

@ -1,850 +0,0 @@
/********************************************************************\
* dialog-qif-import.c -- window for importing QIF files *
* (GnuCash) *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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 *
\********************************************************************/
#define _GNU_SOURCE
#include "top-level.h"
#include <gnome.h>
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <guile/gh.h>
#include "dialog-qif-import.h"
#include "dialog-account-picker.h"
#include "window-help.h"
#include "messages.h"
#include "messages_i18n.h"
#include "gnome-top-level.h"
#include "ui-callbacks.h"
#include "Account.h"
#include "AccInfo.h"
#include "FileDialog.h"
#include "FileBox.h"
#include "dialog-utils.h"
#include "query-user.h"
#include "util.h"
struct _qifimportwindow
{
/* on the Files tab */
GtkWidget * dialog;
GtkWidget * currency_entry;
GtkWidget * filename_entry;
GtkWidget * acct_auto_button;
GtkWidget * acct_entry;
GtkWidget * selected_file_list;
/* on the Accounts tab */
GtkWidget * acct_list;
/* on the Categories tab */
GtkWidget * cat_list;
SCM imported_files;
SCM selected_file;
SCM mapping_info;
SCM cat_display_info;
SCM acct_display_info;
};
static void update_file_info(QIFImportWindow * win, SCM qiffile);
static void update_file_page(QIFImportWindow * win);
static void update_accounts_page(QIFImportWindow * win);
static void update_categories_page(QIFImportWindow * win);
/********************************************************************\
* gnc_ui_qif_import_dialog_make(GtkWidget * parent) * build the
* dialog. For now, there can be only one (obhighlanderref)
\********************************************************************/
QIFImportWindow *
gnc_ui_qif_import_dialog_make(void)
{
QIFImportWindow * retval;
SCM load_map_prefs;
SCM mapping_info;
SCM lookup_option;
SCM lookup_value;
SCM default_currency;
int scm_strlen;
retval = g_new0(QIFImportWindow, 1);
retval->dialog = create_QIF_File_Import_Dialog();
retval->imported_files =
SCM_EOL;
retval->selected_file = SCM_BOOL_F;
retval->currency_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "qif_currency_entry");
retval->filename_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "qif_filename_entry");
retval->acct_auto_button =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "qif_account_auto_check");
retval->acct_entry =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "qif_account_entry");
retval->selected_file_list =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "selected_file_list");
retval->acct_list =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "account_page_list");
retval->cat_list =
gtk_object_get_data(GTK_OBJECT(retval->dialog), "category_page_list");
gtk_object_set_data(GTK_OBJECT(retval->dialog),
"qif_window_struct", retval);
/* load the saved-state of the mappings from Quicken accounts and
* categories to gnucash accounts */
load_map_prefs = gh_eval_str("qif-import:load-map-prefs");
lookup_option = gh_eval_str("gnc:lookup-global-option");
lookup_value = gh_eval_str("gnc:option-value");
mapping_info = gh_call0(load_map_prefs);
retval->mapping_info = mapping_info;
default_currency = gh_call1(lookup_value,
gh_call2(lookup_option,
gh_str02scm("International"),
gh_str02scm("Default Currency")));
scm_protect_object(retval->imported_files);
scm_protect_object(retval->mapping_info);
/* set the currency entry to the GNC default currency */
gtk_entry_set_text(GTK_ENTRY(retval->currency_entry),
gh_scm2newstr(default_currency, &scm_strlen));
gtk_widget_show_all(retval->dialog);
return retval;
}
/********************************************************************\
* gnc_ui_qif_import_dialog_destroy
* close the QIF Import dialog window
\********************************************************************/
void
gnc_ui_qif_import_dialog_destroy (QIFImportWindow * window)
{
if(window) {
gnome_dialog_close(GNOME_DIALOG(window->dialog));
}
scm_unprotect_object(window->imported_files);
scm_unprotect_object(window->selected_file);
scm_unprotect_object(window->mapping_info);
scm_unprotect_object(window->cat_display_info);
scm_unprotect_object(window->acct_display_info);
g_free(window);
}
/********************************************************************\
* gnc_ui_qif_import_select_file_cb
* invoked when the "select file" button is clicked
* this is just to pick a file name and reset-to-defaults all the
* fields describing how to parse the file.
\********************************************************************/
void
gnc_ui_qif_import_select_file_cb(GtkButton * button,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
const char * new_file_name;
new_file_name = fileBox(_("Select QIF File"), "*.qif");
if(new_file_name && (access(new_file_name, R_OK) == 0)) {
/* set the filename entry for what was selected */
if(wind->filename_entry) {
gtk_entry_set_text(GTK_ENTRY(wind->filename_entry),
new_file_name);
}
/* the account should be auto-determined by default
* if the "opening balance" trick doesn't work "auto" will
* use the file name as a guess */
if(wind->acct_auto_button) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wind->acct_auto_button),
TRUE);
}
if(wind->acct_entry) {
gtk_entry_set_text(GTK_ENTRY(wind->acct_entry),
"");
}
}
}
/********************************************************************\
* gnc_ui_qif_import_load_file_cb
*
* Invoked when the "load file" button is clicked on the first page of
* the QIF Import notebook. Filename, currency, and
* date format are read from the UI and passed to the Scheme side.
\********************************************************************/
void
gnc_ui_qif_import_load_file_cb(GtkButton * button, gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
char * path_to_load;
char * qif_account;
char * currency;
char * error_string;
struct timeval start, end;
SCM make_qif_file, qif_file_load, qif_file_loaded, unload_qif_file;
SCM qif_file_parse;
SCM scm_filename, scm_currency, scm_qif_account;
SCM scm_qiffile;
SCM imported_files = SCM_EOL;
SCM load_return, parse_return;
/* get the UI elements */
path_to_load = gtk_entry_get_text(GTK_ENTRY(wind->filename_entry));
currency = gtk_entry_get_text(GTK_ENTRY(wind->currency_entry));
qif_account = gtk_entry_get_text(GTK_ENTRY(wind->acct_entry));
if(strlen(path_to_load) == 0) {
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
_("You must specify a file to load."));
}
else if(strlen(currency) == 0) {
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
_("You must specify a currency."));
}
else {
/* find the make and load functions. */
make_qif_file = gh_eval_str("make-qif-file");
qif_file_load = gh_eval_str("qif-file:read-file");
qif_file_parse = gh_eval_str("qif-file:parse-fields");
qif_file_loaded = gh_eval_str("qif-dialog:qif-file-loaded?");
unload_qif_file = gh_eval_str("qif-dialog:unload-qif-file");
if((!gh_procedure_p(make_qif_file)) ||
(!gh_procedure_p(qif_file_load)) ||
(!gh_procedure_p(qif_file_loaded))) {
gnc_error_dialog_parented
(GTK_WINDOW(wind->dialog),
_("QIF File scheme code not loaded properly."));
}
else {
/* convert args */
scm_filename = gh_str02scm(path_to_load);
scm_currency = gh_str02scm(currency);
if(gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(wind->acct_auto_button))) {
scm_qif_account = gh_symbol2scm("unknown");
}
else {
scm_qif_account = gh_str02scm(qif_account);
}
imported_files = wind->imported_files;
if(gh_call2(qif_file_loaded, scm_filename, wind->imported_files)
== SCM_BOOL_T) {
if(gnc_verify_dialog_parented
(wind->dialog,
_("QIF File already loaded. Reload with current settings?"),
TRUE)) {
imported_files =
gh_call2(unload_qif_file, scm_filename, wind->imported_files);
}
else {
return;
}
}
/* turn on the busy cursor */
gnc_set_busy_cursor(NULL);
gettimeofday(&start, NULL);
/* create the <qif-file> object */
scm_qiffile = gh_apply(make_qif_file,
SCM_LIST2(scm_qif_account, scm_currency));
imported_files =
gh_cons(scm_qiffile, imported_files);
wind->selected_file = scm_qiffile;
scm_protect_object(wind->selected_file);
load_return = gh_call2(qif_file_load, gh_car(imported_files),
scm_filename);
/* a list returned is (#f error-message) for an error,
* (#t error-message) for a warning */
if(gh_list_p(load_return) &&
(gh_car(load_return) == SCM_BOOL_T)) {
error_string = g_strdup_printf(QIF_LOAD_WARNING_FORMAT_MSG,
gh_scm2newstr(gh_cadr(load_return),
NULL));
gnc_warning_dialog_parented(GTK_WIDGET(wind->dialog), error_string);
g_free(error_string);
}
if((load_return != SCM_BOOL_T) &&
(!gh_list_p(load_return) ||
(gh_car(load_return) != SCM_BOOL_T))) {
error_string = g_strdup_printf(QIF_LOAD_FAILED_FORMAT_MSG,
gh_scm2newstr(gh_cadr(load_return),
NULL));
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog), error_string);
g_free(error_string);
imported_files =
gh_call2(unload_qif_file, scm_filename, imported_files);
}
else {
parse_return = gh_call1(qif_file_parse, gh_car(imported_files));
if(gh_list_p(parse_return) &&
(gh_car(parse_return) == SCM_BOOL_T)) {
error_string = g_strdup_printf(QIF_PARSE_WARNING_FORMAT_MSG,
gh_scm2newstr(gh_cadr(parse_return),
NULL));
gnc_warning_dialog_parented(GTK_WIDGET(wind->dialog), error_string);
g_free(error_string);
}
if((parse_return != SCM_BOOL_T) &&
(!gh_list_p(parse_return) ||
(gh_car(parse_return) != SCM_BOOL_T))) {
error_string = g_strdup_printf(QIF_PARSE_FAILED_FORMAT_MSG,
gh_scm2newstr(gh_cadr(parse_return),
NULL));
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog), error_string);
g_free(error_string);
imported_files =
gh_call2(unload_qif_file, scm_filename, imported_files);
}
}
wind->imported_files = imported_files;
scm_protect_object(wind->imported_files);
gettimeofday(&end, NULL);
#if 0
printf("QIF file load took %f ms total.\n",
1000.0*(end.tv_sec - start.tv_sec) +
.001*(end.tv_usec - start.tv_usec));
#endif
gettimeofday(&start, NULL);
/* now update the Accounts and Categories pages in the notebook */
update_file_page(wind);
update_accounts_page(wind);
update_categories_page(wind);
gettimeofday(&end, NULL);
#if 0
printf("QIF Category/account tab update took %f ms.\n",
1000.0*(end.tv_sec - start.tv_sec) +
.001*(end.tv_usec - start.tv_usec));
#endif
gettimeofday(&end, NULL);
/* turn back the cursor */
gnc_unset_busy_cursor(NULL);
}
}
}
void
gnc_ui_qif_import_select_loaded_file_cb(GtkList * list,
GtkWidget * widget,
gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
int file_index =
GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), "file_index"));
wind->selected_file = gh_list_ref(wind->imported_files,
gh_int2scm(file_index));
scm_protect_object(wind->selected_file);
update_file_info(wind, wind->selected_file);
}
/****************************************************************\
* qif_import_ok_cb
* do the work of actually translating QIF xtns to GNC xtns.
\****************************************************************/
void
gnc_ui_qif_import_ok_cb(GtkButton * button, gpointer user_data) {
SCM save_map_prefs = gh_eval_str("qif-import:save-map-prefs");
SCM qif_to_gnc = gh_eval_str("qif-import:qif-to-gnc");
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct");
/* busy cursor */
gnc_set_busy_cursor(NULL);
/* call a scheme function to do the work */
gh_call2(qif_to_gnc, wind->imported_files,
wind->mapping_info);
/* write out mapping info before destroying the window */
gh_call1(save_map_prefs, wind->mapping_info);
gnc_unset_busy_cursor(NULL);
gnc_ui_qif_import_dialog_destroy(wind);
wind = NULL;
}
void
gnc_ui_qif_import_cancel_cb (GtkButton * button, gpointer user_data) {
GtkWidget * dialog = GTK_WIDGET(user_data);
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(dialog), "qif_window_struct");
gnc_ui_qif_import_dialog_destroy(wind);
}
void
gnc_ui_qif_import_help_cb (GtkButton * button, gpointer user_data) {
helpWindow(NULL, HELP_STR, HH_QIFIMPORT);
}
void
gnc_ui_qif_import_account_line_select_cb(GtkCList * clist, gint row,
gint column, GdkEvent * event,
gpointer user_data) {
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct");
char * gnc_acct_text = NULL;
char * qif_acct_text = NULL;
int initial_type;
SCM scm_acct;
SCM mapping_info;
SCM scm_hash_ref = gh_eval_str("hash-ref");
gtk_clist_get_text(GTK_CLIST(clist), row, 0, &qif_acct_text);
gtk_clist_get_text(GTK_CLIST(clist), row, 2, &gnc_acct_text);
mapping_info = gh_call2(scm_hash_ref, gh_cadr(wind->mapping_info),
gh_str02scm(qif_acct_text));
initial_type = gh_scm2int(gh_list_ref(mapping_info, gh_int2scm(2)));
scm_acct = accountPickerBox(gnc_acct_text, initial_type);
if(gh_list_p(scm_acct)) {
scm_list_set_x(mapping_info, gh_int2scm(1), gh_car(scm_acct));
scm_list_set_x(mapping_info, gh_int2scm(2), gh_cadr(scm_acct));
scm_list_set_x(mapping_info, gh_int2scm(5), gh_caddr(scm_acct));
gtk_clist_set_text(GTK_CLIST(clist), row, 2,
gh_scm2newstr(gh_car(scm_acct), NULL));
gtk_clist_set_text(GTK_CLIST(clist), row, 3,
xaccAccountTypeEnumAsString
(gh_scm2int(gh_cadr(scm_acct))));
}
}
void
gnc_ui_qif_import_category_line_select_cb(GtkCList * clist, gint row,
gint column, GdkEvent * event,
gpointer user_data) {
QIFImportWindow * wind =
gtk_object_get_data(GTK_OBJECT(user_data), "qif_window_struct");
char * gnc_acct_text = NULL;
char * qif_acct_text = NULL;
int initial_type;
SCM scm_acct;
SCM mapping_info;
SCM scm_hash_ref = gh_eval_str("hash-ref");
gtk_clist_get_text(GTK_CLIST(clist), row, 0, &qif_acct_text);
gtk_clist_get_text(GTK_CLIST(clist), row, 2, &gnc_acct_text);
mapping_info = gh_call2(scm_hash_ref, gh_caddr(wind->mapping_info),
gh_str02scm(qif_acct_text));
initial_type = gh_scm2int(gh_list_ref(mapping_info, gh_int2scm(2)));
scm_acct = accountPickerBox(gnc_acct_text, initial_type);
if(gh_list_p(scm_acct)) {
scm_list_set_x(mapping_info, gh_int2scm(1), gh_car(scm_acct));
scm_list_set_x(mapping_info, gh_int2scm(2), gh_cadr(scm_acct));
scm_list_set_x(mapping_info, gh_int2scm(5), gh_caddr(scm_acct));
gtk_clist_set_text(GTK_CLIST(clist), row, 2,
gh_scm2newstr(gh_car(scm_acct), NULL));
gtk_clist_set_text(GTK_CLIST(clist), row, 3,
xaccAccountTypeEnumAsString
(gh_scm2int(gh_cadr(scm_acct))));
}
}
/********************************************************************\
* update_file_page
* update the left-side list and the right-side info.
\********************************************************************/
static void
update_file_page(QIFImportWindow * wind) {
GtkWidget * new_list_item;
GList * new_loaded_file;
SCM loaded_file_list = wind->imported_files;
SCM scm_qiffile;
SCM qif_file_path;
int path_strlen;
int scm_file_index = 0;
/* clear the list */
gtk_list_remove_items(GTK_LIST(wind->selected_file_list),
gtk_container_children
(GTK_CONTAINER(wind->selected_file_list)));
qif_file_path = gh_eval_str("qif-file:path");
/* iterate over all the imported files */
while(!gh_null_p(loaded_file_list)) {
scm_qiffile = gh_car(loaded_file_list);
/* make a list item with the SCM object attached as data */
new_list_item =
gtk_list_item_new_with_label(gh_scm2newstr(gh_call1(qif_file_path,
scm_qiffile),
&path_strlen));
gtk_object_set_data(GTK_OBJECT(new_list_item),
"file_index", GINT_TO_POINTER(scm_file_index));
scm_file_index++;
/* tack it on to the displayed list */
new_loaded_file = g_list_alloc();
new_loaded_file->next = NULL;
new_loaded_file->prev = NULL;
gtk_widget_show(new_list_item);
new_loaded_file->data = new_list_item;
/* now add the file to the loaded-files list */
gtk_list_append_items(GTK_LIST(wind->selected_file_list),
new_loaded_file);
/* select_child will update the file info */
if(scm_qiffile == wind->selected_file) {
gtk_list_select_child(GTK_LIST(wind->selected_file_list), new_list_item);
}
loaded_file_list = gh_cdr(loaded_file_list);
}
}
/********************************************************************\
* update_file_info
*
* Invoked when a file is loaded or the name of a loaded file is
* clicked in the loaded files list. This causes the pickers and text
* boxes on the right side to be updated to reflect the actual values
* used or detected in loading the files.
\********************************************************************/
static void
update_file_info(QIFImportWindow * wind, SCM qif_file) {
SCM qif_file_currency;
SCM qif_file_path;
SCM qif_file_account;
SCM scm_currency;
SCM scm_qif_account;
SCM scm_qif_path;
int scm_strlen;
/* look up the <qif-file> methods */
qif_file_currency = gh_eval_str("qif-file:currency");
qif_file_path = gh_eval_str("qif-file:path");
qif_file_account = gh_eval_str("qif-file:default-account");
/* make sure the methods are loaded */
if((!gh_procedure_p(qif_file_currency)) ||
(!gh_procedure_p(qif_file_account)) ||
(!gh_procedure_p(qif_file_path))) {
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
_("QIF File scheme code not loaded properly."));
return;
}
else {
/* get the currency etc from the Scheme side */
scm_currency = gh_call1(qif_file_currency,
qif_file);
scm_qif_path = gh_call1(qif_file_path,
qif_file);
scm_qif_account = gh_call1(qif_file_account,
qif_file);
/* put the data in the info fields */
gtk_entry_set_text(GTK_ENTRY(wind->filename_entry),
gh_scm2newstr(scm_qif_path, &scm_strlen));
gtk_entry_set_text(GTK_ENTRY(wind->currency_entry),
gh_scm2newstr(scm_currency, &scm_strlen));
/* account is weird. after loading, either we know it or we don't
* but in either case the auto should be off. */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wind->acct_auto_button),
FALSE);
gtk_entry_set_text(GTK_ENTRY(wind->acct_entry),
gh_scm2newstr(scm_qif_account, &scm_strlen));
}
}
/****************************************************************\
* update_accounts_page
* Ask the Scheme side to guess some account translations , then
* show the filename, account name, and suggested translation in
* the Accounts page clist.
\****************************************************************/
static void
update_accounts_page(QIFImportWindow * wind) {
SCM make_account_display;
SCM strings_left;
SCM display_info;
SCM hash_data;
SCM hash_set;
int xtn_count;
char * xtn_count_string;
char * qif_acct_name;
int row;
int scheme_strlen;
char * row_text[4];
make_account_display = gh_eval_str("qif-dialog:make-account-display");
hash_set = gh_eval_str("hash-set!");
/* make sure we found the procedure */
if(!gh_procedure_p(make_account_display)) {
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
_("QIF File scheme code not loaded properly."));
return;
}
/* transfer the existing info from the account picker to
* the mapping info hash table */
for(row=0; row < GTK_CLIST(wind->acct_list)->rows; row++) {
gtk_clist_get_text(GTK_CLIST(wind->acct_list), row, 0, &qif_acct_name);
hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(wind->acct_list), row);
gh_call3(hash_set, gh_cadr(wind->mapping_info),
gh_str02scm(qif_acct_name),
hash_data);
}
/* now get the list of strings to display in the clist widget */
/* gnc_unprotect_object(wind->acct_display_info); */
display_info = gh_call2(make_account_display,
wind->imported_files,
wind->mapping_info);
wind->acct_display_info = display_info;
scm_protect_object(wind->acct_display_info);
strings_left = wind->acct_display_info;
if(!gh_list_p(strings_left)) {
gnc_error_dialog_parented
(GTK_WINDOW(wind->dialog),
_("Something is very wrong with QIF Importing."));
return;
}
/* clear the list */
gtk_clist_clear(GTK_CLIST(wind->acct_list));
/* update the text in the boxes */
gtk_clist_freeze(GTK_CLIST(wind->acct_list));
gtk_clist_set_column_justification(GTK_CLIST(wind->acct_list),
0,
GTK_JUSTIFY_RIGHT);
row = 0;
while(!gh_null_p(strings_left)) {
row_text[0] = gh_scm2newstr(gh_caar(strings_left), &scheme_strlen);
xtn_count = gh_scm2int(gh_list_ref(gh_car(strings_left),
gh_int2scm(4)));
xtn_count_string = g_strdup_printf("%d", xtn_count);
row_text[1] = xtn_count_string;
row_text[2] = gh_scm2newstr(gh_cadr(gh_car(strings_left)),
&scheme_strlen);
row_text[3] =
xaccAccountTypeEnumAsString(gh_scm2int
(gh_caddr(gh_car(strings_left))));
gtk_clist_append(GTK_CLIST(wind->acct_list), row_text);
gtk_clist_set_row_data(GTK_CLIST(wind->acct_list), row,
GINT_TO_POINTER((gh_car(strings_left))));
scm_protect_object(gh_car(strings_left));
strings_left = gh_cdr(strings_left);
row++;
free(row_text[0]);
g_free(row_text[1]);
free(row_text[2]);
}
gtk_clist_thaw(GTK_CLIST(wind->acct_list));
}
/****************************************************************\
* update_categories_page
* Ask the Scheme side to guess some account translations , then
* show the filename, account name, and suggested translation in
* the Accounts page clist.
\****************************************************************/
static void
update_categories_page(QIFImportWindow * wind) {
SCM make_category_display;
SCM strings_left;
SCM display_info;
SCM hash_data;
SCM hash_set;
int xtn_count;
char * xtn_count_string;
char * qif_cat_name;
int row;
int scheme_strlen;
char * row_text[4];
make_category_display = gh_eval_str("qif-dialog:make-category-display");
hash_set = gh_eval_str("hash-set!");
/* make sure we found the procedure */
if(!gh_procedure_p(make_category_display)) {
gnc_error_dialog_parented(GTK_WINDOW(wind->dialog),
_("QIF File scheme code not loaded properly."));
return;
}
/* get the existing mappings from the display */
for(row=0; row < GTK_CLIST(wind->cat_list)->rows; row++) {
gtk_clist_get_text(GTK_CLIST(wind->cat_list), row, 0, &qif_cat_name);
hash_data = (SCM)gtk_clist_get_row_data(GTK_CLIST(wind->cat_list), row);
gh_call3(hash_set, gh_caddr(wind->mapping_info),
gh_str02scm(qif_cat_name),
hash_data);
}
/* now get the list of strings to display in the clist widget */
/* gnc_unprotect_object(wind->cat_display_info); */
display_info = gh_call2(make_category_display,
wind->imported_files,
wind->mapping_info);
wind->cat_display_info = display_info;
scm_protect_object(wind->cat_display_info);
strings_left = wind->cat_display_info;
if(!gh_list_p(strings_left)) {
gnc_error_dialog_parented
(GTK_WINDOW(wind->dialog),
_("Something is very wrong with QIF Importing."));
return;
}
/* clear the list */
gtk_clist_clear(GTK_CLIST(wind->cat_list));
/* update the text in the boxes */
gtk_clist_freeze(GTK_CLIST(wind->cat_list));
gtk_clist_set_column_justification(GTK_CLIST(wind->cat_list),
0,
GTK_JUSTIFY_RIGHT);
row = 0;
while(!gh_null_p(strings_left)) {
row_text[0] = gh_scm2newstr(gh_caar(strings_left), &scheme_strlen);
xtn_count = gh_scm2int(gh_list_ref(gh_car(strings_left),
gh_int2scm(4)));
xtn_count_string = g_strdup_printf("%d", xtn_count);
row_text[1] = xtn_count_string;
row_text[2] = gh_scm2newstr(gh_cadr(gh_car(strings_left)),
&scheme_strlen);
row_text[3] = xaccAccountTypeEnumAsString(gh_scm2int
(gh_caddr(gh_car(strings_left))));
gtk_clist_append(GTK_CLIST(wind->cat_list), row_text);
gtk_clist_set_row_data(GTK_CLIST(wind->cat_list), row,
GINT_TO_POINTER(gh_car(strings_left)));
scm_protect_object(gh_car(strings_left));
strings_left = gh_cdr(strings_left);
row++;
free(row_text[0]);
g_free(row_text[1]);
free(row_text[2]);
}
gtk_clist_thaw(GTK_CLIST(wind->cat_list));
}

View File

@ -104,7 +104,6 @@ gnc_xfer_dialog_fill_tree_frame(XferDialog *xferData,
xferData->to = atree;
else
xferData->from = atree;
gtk_clist_column_titles_hide(GTK_CLIST(tree));
gnc_account_tree_hide_all_but_name(GNC_ACCOUNT_TREE(tree));
gnc_account_tree_hide_income_expense(GNC_ACCOUNT_TREE(tree));
@ -169,21 +168,20 @@ gnc_parse_error_dialog (XferDialog *xferData)
static gboolean
gnc_xfer_update_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
{
XferDialog *xferData = data;
const char *currency;
Account *account;
XferDialog * xferData = data;
Account * account;
const gnc_commodity * currency;
account = gnc_account_tree_get_current_account(xferData->from);
if (account == NULL)
account = gnc_account_tree_get_current_account(xferData->to);
currency = xaccAccountGetCurrency(account);
gnc_amount_edit_set_currency (GNC_AMOUNT_EDIT (xferData->amount_edit),
currency);
gnc_commodity_get_printname(currency));
gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->amount_edit));
return FALSE;
}
@ -267,8 +265,8 @@ gnc_xfer_dialog_select_to_account(XferDialog *xferData, Account *account)
void
gnc_xfer_dialog_set_amount(XferDialog *xferData, double amount)
{
Account *account;
const char *currency;
Account * account;
const gnc_commodity * currency;
if (xferData == NULL)
return;
@ -276,12 +274,12 @@ gnc_xfer_dialog_set_amount(XferDialog *xferData, double amount)
account = gnc_account_tree_get_current_account(xferData->from);
if (account == NULL)
account = gnc_account_tree_get_current_account(xferData->to);
currency = xaccAccountGetCurrency(account);
gnc_amount_edit_set_currency (GNC_AMOUNT_EDIT (xferData->amount_edit),
currency);
gnc_commodity_get_printname(currency));
gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->amount_edit), amount);
}
@ -363,11 +361,11 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
/* first split is already there */
to_split = xaccTransGetSplit(trans, 0);
xaccSplitSetShareAmount(to_split, amount);
DxaccSplitSetShareAmount(to_split, amount);
/* second split must be created */
from_split = xaccMallocSplit();
xaccSplitSetShareAmount(from_split, -amount);
DxaccSplitSetShareAmount(from_split, -amount);
xaccTransAppendSplit(trans, from_split);
/* TransSetMemo will set the memo for both splits */
@ -375,12 +373,12 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
xaccTransSetMemo(trans, string);
/* Now do the 'to' account */
xaccAccountBeginEdit(to, FALSE);
xaccAccountBeginEdit(to);
xaccAccountInsertSplit(to, to_split);
xaccAccountCommitEdit(to);
/* Now do the 'from' account */
xaccAccountBeginEdit(from, FALSE);
xaccAccountBeginEdit(from);
xaccAccountInsertSplit(from, from_split);
xaccAccountCommitEdit(from);
@ -471,14 +469,13 @@ gnc_xfer_dialog_create(GtkWidget * parent, XferDialog *xferData)
xferData->amount_edit = amount;
entry = gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (amount));
gtk_signal_connect(GTK_OBJECT(entry), "focus-out-event",
GTK_SIGNAL_FUNC(gnc_xfer_update_cb), xferData);
gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
date = gnc_date_edit_new(time(NULL), FALSE, FALSE);
hbox = gtk_object_get_data(tdo, "date_hbox");
gtk_box_pack_end(GTK_BOX(hbox), date, TRUE, TRUE, 0);
xferData->date_entry = date;
}

View File

@ -28,7 +28,7 @@
#include "account-tree.h"
#include "dialog-utils.h"
#include "global-options.h"
#include "gnc-currency-edit.h"
#include "gnc-commodity.h"
#include "messages.h"
#include "EuroUtils.h"
#include "util.h"
@ -129,9 +129,7 @@ gnc_ui_source_menu_create(Account *account)
GtkMenu *menu;
GtkWidget *item;
GtkWidget *omenu;
gchar *codename;
AccInfo *accinfo;
InvAcct *invacct;
/* gchar *codename; This didn't appear to be used anywhere... */
GNCAccountType type;
menu = GTK_MENU(gtk_menu_new());
@ -156,12 +154,12 @@ gnc_ui_source_menu_create(Account *account)
if ((STOCK != type) && (MUTUAL != type) && (CURRENCY != type))
return omenu;
accinfo = xaccAccountGetAccInfo(account);
invacct = xaccCastToInvAcct(accinfo);
if (invacct == NULL)
if ((STOCK != type) && (MUTUAL != type))
return omenu;
codename = xaccInvAcctGetPriceSrc(invacct);
/*
This didn't appear to be used anywhere...
codename = xaccInvAcctGetPriceSrc(invacct); */
return omenu;
}
@ -223,14 +221,14 @@ gnc_ui_account_get_balance(Account *account, gboolean include_children)
if (account == NULL)
return 0.0;
balance = xaccAccountGetBalance (account);
balance = DxaccAccountGetBalance (account);
if (include_children)
{
AccountGroup *children;
children = xaccAccountGetChildren (account);
balance += xaccGroupGetBalance (children);
balance += DxaccGroupGetBalance (children);
}
/* reverse sign if needed */
@ -267,43 +265,47 @@ gnc_ui_get_account_field_value_string(Account *account, int field)
return xaccAccountGetNotes(account);
break;
case ACCOUNT_CURRENCY :
return xaccAccountGetCurrency(account);
return gnc_commodity_get_printname(xaccAccountGetCurrency(account));
break;
case ACCOUNT_SECURITY :
return xaccAccountGetSecurity(account);
return gnc_commodity_get_printname(xaccAccountGetSecurity(account));
break;
case ACCOUNT_BALANCE :
{
double balance = gnc_ui_account_get_balance(account, FALSE);
return xaccPrintAmount(balance, PRTSYM | PRTSEP,
xaccAccountGetCurrency(account));
return DxaccPrintAmount(balance, PRTSYM | PRTSEP,
gnc_commodity_get_mnemonic
(xaccAccountGetCurrency(account)));
}
break;
case ACCOUNT_BALANCE_EURO :
{
const char *account_currency = xaccAccountGetCurrency(account);
const gnc_commodity * account_currency =
xaccAccountGetCurrency(account);
double balance = gnc_ui_account_get_balance(account, FALSE);
double euro_balance = gnc_convert_to_euro(account_currency, balance);
return xaccPrintAmount(euro_balance, PRTSYM | PRTSEP | PRTEUR, NULL);
return DxaccPrintAmount(euro_balance, PRTSYM | PRTSEP | PRTEUR, NULL);
}
break;
case ACCOUNT_TOTAL :
{
double balance = gnc_ui_account_get_balance(account, TRUE);
return xaccPrintAmount(balance, PRTSYM | PRTSEP,
xaccAccountGetCurrency(account));
return DxaccPrintAmount(balance, PRTSYM | PRTSEP,
gnc_commodity_get_mnemonic
(xaccAccountGetCurrency(account)));
}
break;
case ACCOUNT_TOTAL_EURO :
{
const char *account_currency = xaccAccountGetCurrency(account);
const gnc_commodity * account_currency =
xaccAccountGetCurrency(account);
double balance = gnc_ui_account_get_balance(account, TRUE);
double euro_balance = gnc_convert_to_euro(account_currency, balance);
return xaccPrintAmount(euro_balance, PRTSYM | PRTSEP | PRTEUR, NULL);
return DxaccPrintAmount(euro_balance, PRTSYM | PRTSEP | PRTEUR, NULL);
}
break;
}

416
src/gnome/druid-commodity.c Normal file
View File

@ -0,0 +1,416 @@
/********************************************************************
* druid-commodity.c -- fancy importer for old Gnucash files *
* (GnuCash) *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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 *
********************************************************************/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <glib.h>
#include <assert.h>
#include "FileDialog.h"
#include "druid-commodity.h"
#include "dialog-commodity.h"
#include "query-user.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
struct _commoditydruid {
GtkWidget * window;
GtkWidget * druid;
GtkWidget * intro_page;
GtkWidget * finish_page;
GHashTable * new_map;
GHashTable * old_map;
GList * pages;
int is_modal;
};
struct _commoditydruidpage {
GtkWidget * page;
char * old_name;
GtkWidget * new_type_combo;
GtkWidget * new_type_entry;
GtkWidget * new_name_entry;
GtkWidget * new_mnemonic_entry;
};
typedef struct _commoditydruidpage CommodityDruidPage;
static CommodityDruidPage * make_commodity_druid_page(gnc_commodity * comm);
static GdkColor std_bg_color = { 0, 39835, 49087, 40092 };
static GdkColor std_logo_bg_color = { 0, 65535, 65535, 65535 };
static GdkColor std_title_color = { 0, 65535, 65535, 65535 };
static int gnc_ui_commodity_druid_comm_check_cb(GnomeDruidPage * page,
gpointer druid,
gpointer user_data);
void
gnc_import_legacy_commodities(char * filename) {
CommodityDruid * d = gnc_ui_commodity_druid_create(filename);
d->is_modal = TRUE;
gtk_window_set_modal(GTK_WINDOW(d->window), TRUE);
gtk_main();
}
/********************************************************************
* gnc_ui_commodity_druid_create()
********************************************************************/
CommodityDruid *
gnc_ui_commodity_druid_create(const char * filename) {
CommodityDruid * d = g_new0(CommodityDruid, 1);
GtkObject * dobj;
GList * orphans, * l;
gnc_commodity * lost;
gnc_commodity * found;
CommodityDruidPage * new_page;
GnomeDruidPage * back_page;
/* call the glade creator */
d->window = create_New_Commodity_Format_Druid();
dobj = GTK_OBJECT(d->window);
d->druid = gtk_object_get_data(dobj, "commodity_druid");
d->intro_page = gtk_object_get_data(dobj, "start_page");
d->finish_page = gtk_object_get_data(dobj, "finish_page");
back_page = GNOME_DRUID_PAGE(d->intro_page);
d->is_modal = FALSE;
gtk_object_set_data(dobj, "commodity_druid_struct", (gpointer)d);
d->new_map = g_hash_table_new(g_str_hash, g_str_equal);
d->old_map = g_hash_table_new(g_str_hash, g_str_equal);
orphans =
gnc_commodity_table_get_commodities(gnc_engine_commodities(),
GNC_COMMODITY_NS_LEGACY);
gnc_commodity_table_delete_namespace(gnc_engine_commodities(),
GNC_COMMODITY_NS_LEGACY);
/* make a new list with the (saved) old mnemonic and the
* new currency. */
for(l=orphans; l; l=l->next) {
lost = (gnc_commodity *)l->data;
/* if the mnemonic is an ISO-4217 currency, use that as
* the default */
found = gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
gnc_commodity_get_mnemonic(lost));
/* otherwise, guess that it's a NASDAQ security. */
if(!found) {
found = gnc_commodity_new(gnc_commodity_get_mnemonic(lost),
GNC_COMMODITY_NS_NASDAQ,
gnc_commodity_get_mnemonic(lost),
NULL, 1000);
}
g_hash_table_insert(d->new_map, (gpointer)gnc_commodity_get_mnemonic(lost),
(gpointer)found);
g_hash_table_insert(d->old_map, (gpointer)gnc_commodity_get_mnemonic(lost),
(gpointer)lost);
/* create a new page in the wizard for the commodity */
new_page = make_commodity_druid_page(found);
/* set up next/back signal handlers */
gtk_signal_connect(GTK_OBJECT (new_page->page), "next",
GTK_SIGNAL_FUNC(gnc_ui_commodity_druid_comm_check_cb),
d->window);
gtk_signal_connect(GTK_OBJECT(new_page->page), "cancel",
GTK_SIGNAL_FUNC(gnc_ui_commodity_druid_cancel_cb),
d->window);
d->pages = g_list_append(d->pages, new_page);
gnome_druid_insert_page(GNOME_DRUID(d->druid),
back_page,
GNOME_DRUID_PAGE(new_page->page));
back_page = GNOME_DRUID_PAGE(new_page->page);
}
gtk_widget_show_all(d->window);
return d;
}
/********************************************************************
* make_commodity_druid_page : build a single commodity xlator
* page. This really should be done in glade, but I can't figure out
* how to make it work.
********************************************************************/
static CommodityDruidPage *
make_commodity_druid_page(gnc_commodity * comm) {
CommodityDruidPage * retval = g_new0(CommodityDruidPage, 1);
GtkWidget * alignment;
GtkWidget * top_vbox;
GtkWidget * info_label;
GtkWidget * next_label;
GtkWidget * temp;
char * title = NULL;
GnomeDruidPageStandard * page;
/* make the page widget */
retval->page = gnome_druid_page_standard_new_with_vals("", NULL);
gtk_object_set_data(GTK_OBJECT(retval->page),
"page_struct", (gpointer)retval);
page = GNOME_DRUID_PAGE_STANDARD(retval->page);
/* save the old commodity name */
retval->old_name = g_strdup(gnc_commodity_get_mnemonic(comm));
title = g_strdup_printf("Enter information about \"%s\"",
retval->old_name);
gnome_druid_page_standard_set_bg_color(page, & std_bg_color);
gnome_druid_page_standard_set_logo_bg_color(page, & std_logo_bg_color);
gnome_druid_page_standard_set_title_color(page, & std_title_color);
gnome_druid_page_standard_set_title(page, title);
g_free(title);
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start(GTK_BOX(page->vbox), alignment, FALSE, FALSE, 0);
top_vbox = gtk_vbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(alignment), top_vbox);
info_label =
gtk_label_new(_("Pick the type of the currency or security. For "
"national currencies, \nuse \"ISO4217\". "
"Enter a new type in the box if the ones in the\n"
"pick list are inappropriate."));
gtk_label_set_justify (GTK_LABEL(info_label), GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(top_vbox), info_label, TRUE, TRUE, 0);
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 0);
retval->new_type_combo = gtk_combo_new();
gtk_box_pack_start(GTK_BOX(temp), retval->new_type_combo, TRUE, TRUE, 0);
retval->new_type_entry = (GTK_COMBO(retval->new_type_combo))->entry;
gnc_ui_update_namespace_picker(retval->new_type_combo,
gnc_commodity_get_namespace(comm));
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 5);
info_label =
gtk_label_new(_("Enter a descriptive name for the currency or stock, "
"such as \n\"US Dollar\" or \"Red Hat Stock\""));
gtk_label_set_justify (GTK_LABEL(info_label), GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(top_vbox), info_label, TRUE, TRUE, 0);
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 0);
retval->new_name_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(temp), retval->new_name_entry,
TRUE, TRUE, 0);
gtk_entry_set_text(GTK_ENTRY(retval->new_name_entry),
gnc_commodity_get_fullname(comm));
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 5);
info_label =
gtk_label_new(_("Enter the ticker symbol (such as \"RHAT\"), "
"ISO currency symbol \n(such as \"USD\"), or "
"other unique abbreviation for the name."));
gtk_label_set_justify (GTK_LABEL(info_label), GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(top_vbox), info_label, TRUE, TRUE, 0);
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 0);
retval->new_mnemonic_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(temp), retval->new_mnemonic_entry,
TRUE, TRUE, 0);
gtk_entry_set_text(GTK_ENTRY(retval->new_mnemonic_entry),
gnc_commodity_get_mnemonic(comm));
temp = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(top_vbox), temp, FALSE, FALSE, 5);
next_label = gtk_label_new(_("Click \"Next\" to accept the information "
"and move \nto the next currency or stock."));
gtk_label_set_justify (GTK_LABEL(next_label), GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(top_vbox), next_label, TRUE, TRUE, 0);
return retval;
}
/********************************************************************
* gnc_ui_commodity_druid_destroy()
********************************************************************/
void
gnc_ui_commodity_druid_destroy(CommodityDruid * cd) {
GList * p;
CommodityDruidPage * cdp;
for(p=cd->pages; p; p=p->next) {
cdp = (CommodityDruidPage *)p->data;
g_free(cdp->old_name);
g_free(cdp);
}
g_list_free(cd->pages);
g_hash_table_destroy(cd->new_map);
g_hash_table_destroy(cd->old_map);
gtk_widget_destroy(GTK_WIDGET(cd->window));
if(cd->is_modal) {
gtk_main_quit();
}
}
/********************************************************************
* callbacks
********************************************************************/
gboolean
gnc_ui_commodity_druid_cancel_cb(GnomeDruidPage * page, gpointer druid,
gpointer user_data) {
CommodityDruid * cd =
(CommodityDruid *)gtk_object_get_data(GTK_OBJECT(user_data),
"commodity_druid_struct");
/* unload the current file (can't have out-of-date commodities) */
gncFileQuit();
gnc_refresh_main_window();
/* destroy the dialog */
gnc_ui_commodity_druid_destroy(cd);
return TRUE;
}
static gboolean
gnc_ui_commodity_druid_comm_check_cb(GnomeDruidPage * page, gpointer druid,
gpointer user_data) {
CommodityDruid * cd =
(CommodityDruid *)gtk_object_get_data(GTK_OBJECT(user_data),
"commodity_druid_struct");
CommodityDruidPage * dpage =
(CommodityDruidPage *)gtk_object_get_data(GTK_OBJECT(page),
"page_struct");
char * new_type;
char * new_name;
char * new_mnemonic;
gnc_commodity * new_comm;
new_type = gtk_entry_get_text(GTK_ENTRY(dpage->new_type_entry));
new_name = gtk_entry_get_text(GTK_ENTRY(dpage->new_name_entry));
new_mnemonic = gtk_entry_get_text(GTK_ENTRY(dpage->new_mnemonic_entry));
if((strlen(new_type) == 0) ||
(strlen(new_name) == 0) ||
(strlen(new_mnemonic) == 0)) {
gnc_warning_dialog(_("You must put values for the type, name,\n"
"and abbreviation of the currency/stock."));
return TRUE;
}
else {
new_comm = g_hash_table_lookup(cd->new_map, dpage->old_name);
assert(new_comm);
/* fill in the commodity structure info */
gnc_commodity_set_fullname(new_comm, new_name);
gnc_commodity_set_namespace(new_comm, new_type);
gnc_commodity_set_mnemonic(new_comm, new_mnemonic);
return FALSE;
}
}
static void
finish_helper(gpointer key, gpointer value, gpointer data) {
CommodityDruid * cd = data;
gnc_commodity * comm = value;
gnc_commodity * old_comm = g_hash_table_lookup(cd->old_map,
key);
Account ** accts;
Account ** current;
/* key is the old mnemonic, value is a pointer to the gnc_commodity
* structure. */
gnc_commodity_table_insert(gnc_engine_commodities(), comm);
/* now replace all the accounts using old_comm with new_comm */
accts = xaccGetAccounts(gncGetCurrentGroup());
for(current = accts; *current; current++) {
xaccAccountBeginEdit(*current);
if(gnc_commodity_equiv(xaccAccountGetCurrency(*current),
old_comm)) {
xaccAccountSetCurrency(*current, comm);
}
if(gnc_commodity_equiv(xaccAccountGetSecurity(*current),
old_comm)) {
xaccAccountSetSecurity(*current, comm);
}
xaccAccountCommitEdit(*current);
}
}
void
gnc_ui_commodity_druid_finish_cb(GnomeDruidPage * page, gpointer druid,
gpointer user_data) {
CommodityDruid * cd =
(CommodityDruid *)gtk_object_get_data(GTK_OBJECT(user_data),
"commodity_druid_struct");
/* add the new commodities to the engine's namespace map and
* replace the account commodity pointers */
g_hash_table_foreach(cd->new_map, &finish_helper, (gpointer)cd);
/* destroy the dialog */
gnc_ui_commodity_druid_destroy(cd);
gnc_refresh_main_window();
}

View File

@ -0,0 +1,46 @@
/********************************************************************
* druid-commodity.h -- fancy importer for old Gnucash files *
* (GnuCash) *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* 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 __DRUID_COMMODITY_H__
#define __DRUID_COMMODITY_H__
#include <gtk/gtk.h>
#include <gnome.h>
#include "glade-gnc-dialogs.h"
#include "glade-cb-gnc-dialogs.h"
#include "ui-callbacks.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
typedef struct _commoditydruid CommodityDruid;
/* create/destroy commodity import druid */
CommodityDruid * gnc_ui_commodity_druid_create(const char * filename);
void gnc_ui_commodity_druid_destroy(CommodityDruid * d);
/* invoke import druid modally */
void gnc_import_legacy_commodities(char * filename);
#endif

1228
src/gnome/druid-qif-import.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -30,5 +30,7 @@
#include "glade-cb-gnc-dialogs.h"
#include "ui-callbacks.h"
QIFImportWindow * gnc_ui_qif_import_druid_make(void);
void gnc_ui_qif_import_druid_destroy (QIFImportWindow * window);
#endif

View File

@ -1,48 +1,6 @@
#include <gnome.h>
void
gnc_ui_qif_import_select_loaded_file_cb
(GtkList *list,
GtkWidget *widget,
gpointer user_data);
void
gnc_ui_qif_import_select_file_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_load_file_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_account_line_select_cb
(GtkCList *clist,
gint row,
gint column,
GdkEvent *event,
gpointer user_data);
void
gnc_ui_qif_import_category_line_select_cb
(GtkCList *clist,
gint row,
gint column,
GdkEvent *event,
gpointer user_data);
void
gnc_ui_qif_import_ok_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_cancel_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_help_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_account_picker_select_cb (GtkTree *tree,
GtkWidget *widget,
@ -105,13 +63,13 @@ gnc_ui_print_check_dialog_help_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_find_transactions_dialog_early_date_select_cb
(GtkButton *button,
gnc_ui_find_transactions_dialog_early_date_toggle_cb
(GtkToggleButton *togglebutton,
gpointer user_data);
void
gnc_ui_find_transactions_dialog_late_date_select_cb
(GtkButton *button,
gnc_ui_find_transactions_dialog_late_date_toggle_cb
(GtkToggleButton *togglebutton,
gpointer user_data);
void
@ -134,13 +92,145 @@ gnc_ui_find_transactions_dialog_help_cb
gpointer user_data);
void
gnc_ui_select_date_dialog_today_cb (GtkButton *button,
gnc_ui_select_commodity_namespace_changed_cb
(GtkEditable *editable,
gpointer user_data);
void
gnc_ui_select_date_dialog_ok_cb (GtkButton *button,
gnc_ui_select_commodity_ok_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_select_date_dialog_cancel_cb (GtkButton *button,
gnc_ui_select_commodity_new_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_select_commodity_cancel_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_new_commodity_ok_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_new_commodity_cancel_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_new_commodity_help_cb (GtkButton *button,
gpointer user_data);
void
gnc_account_window_select_currency_cb (GtkButton *button,
gpointer user_data);
void
gnc_account_window_select_security_cb (GtkButton *button,
gpointer user_data);
gboolean
gnc_ui_commodity_druid_cancel_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_commodity_druid_finish_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_cancel_cb (GnomeDruid *gnomedruid,
gpointer user_data);
gboolean
gnc_ui_qif_import_load_file_next_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_select_file_cb (GtkButton *button,
gpointer user_data);
gboolean
gnc_ui_qif_import_date_format_next_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
gboolean
gnc_ui_qif_import_default_acct_next_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
gboolean
gnc_ui_qif_import_default_acct_back_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_loaded_files_prepare_cb
(GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_select_loaded_file_cb
(GtkCList *clist,
gint row,
gint column,
GdkEvent *event,
gpointer user_data);
void
gnc_ui_qif_import_load_another_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_unload_file_cb (GtkButton *button,
gpointer user_data);
void
gnc_ui_qif_import_accounts_prepare_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_account_line_select_cb
(GtkCList *clist,
gint row,
gint column,
GdkEvent *event,
gpointer user_data);
void
gnc_ui_qif_import_categories_prepare_cb
(GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
gboolean
gnc_ui_qif_import_categories_next_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_category_line_select_cb
(GtkCList *clist,
gint row,
gint column,
GdkEvent *event,
gpointer user_data);
gboolean
gnc_ui_qif_import_currency_next_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_commodity_prepare_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);
void
gnc_ui_qif_import_finish_cb (GnomeDruidPage *gnomedruidpage,
gpointer arg1,
gpointer user_data);

File diff suppressed because it is too large Load Diff

View File

@ -2,17 +2,19 @@
* DO NOT EDIT THIS FILE - it is generated by Glade.
*/
GtkWidget* create_QIF_File_Import_Dialog (void);
GtkWidget* create_QIF_Import_Account_Picker (void);
GtkWidget* create_Print_Preview_Dialog (void);
GtkWidget* create_Print_Dialog (void);
GtkWidget* create_Paper_Size_Selector_Dialog (void);
GtkWidget* create_Print_Check_Dialog (void);
GtkWidget* create_Find_Transactions (void);
GtkWidget* create_Select_Date (void);
GtkWidget* create_Budget_Dialog (void);
GtkWidget* create_Financial_Calculator_Dialog (void);
GtkWidget* create_Amortization_Schedule_Dialog (void);
GtkWidget* create_Commodity_Selector_Dialog (void);
GtkWidget* create_New_Commodity_Dialog (void);
GtkWidget* create_Account_Dialog (void);
GtkWidget* create_New_Commodity_Format_Druid (void);
GtkWidget* create_QIF_Import_Druid (void);
GtkWidget* create_Transfer_Dialog (void);
GtkWidget* create_Progress_Dialog (void);

View File

@ -319,7 +319,7 @@ gnc_amount_edit_set_amount (GNCAmountEdit *gae, double amount)
gae->amount = amount;
gae->need_to_parse = FALSE;
amount_string = xaccPrintAmount (amount, gae->print_flags, gae->currency);
amount_string = DxaccPrintAmount (amount, gae->print_flags, gae->currency);
gtk_entry_set_text (GTK_ENTRY (gae->amount_entry), amount_string);
}

File diff suppressed because it is too large Load Diff

View File

@ -74,9 +74,11 @@ static gint gtk_select_list_enter (GtkWidget *widget,
static gint gtk_select_list_key_press (GtkWidget *widget,
GdkEventKey *event,
GtkSelect *select);
//static gint gtk_select_entry_key_press (GtkEntry *widget,
// GdkEventKey *event,
// GtkSelect *select);
#if 0
static gint gtk_select_entry_key_press (GtkEntry *widget,
GdkEventKey *event,
GtkSelect *select);
#endif
static void gtk_select_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);

View File

@ -185,7 +185,7 @@ void
gnc_ui_print_dialog_select_printer_cb(GtkButton * button, gpointer user_data) {
PrintDialog * pcd;
GnomePrinter * printer;
char * printer_string;
/* char * printer_string; */
if(user_data) {
pcd = gtk_object_get_data(GTK_OBJECT(user_data), "print_struct");

View File

@ -116,10 +116,10 @@ gnc_reconcile_list_new(Account *account, GNCReconcileListType type)
xaccQueryAddSingleAccountMatch(list->query, account, QUERY_OR);
if (type == RECLIST_CREDIT)
xaccQueryAddAmountMatch(list->query, 0.0, AMT_SGN_MATCH_CREDIT,
DxaccQueryAddAmountMatch(list->query, 0.0, AMT_SGN_MATCH_CREDIT,
AMT_MATCH_ATLEAST, QUERY_AND);
else
xaccQueryAddAmountMatch(list->query, 0.0, AMT_SGN_MATCH_DEBIT,
DxaccQueryAddAmountMatch(list->query, 0.0, AMT_SGN_MATCH_DEBIT,
AMT_MATCH_ATLEAST, QUERY_AND);
return GTK_WIDGET(list);
@ -513,9 +513,9 @@ gnc_reconcile_list_reconciled_balance(GNCReconcileList *list)
if ((account_type == STOCK) || (account_type == MUTUAL) ||
(account_type == CURRENCY))
total += xaccSplitGetShareAmount(split);
total += DxaccSplitGetShareAmount(split);
else
total += xaccSplitGetValue(split);
total += DxaccSplitGetValue(split);
}
return DABS(total);
@ -634,7 +634,7 @@ gnc_reconcile_list_fill(GNCReconcileList *list)
Split **splits;
Split *split;
const char *currency;
const gnc_commodity * currency;
char recn;
double amount;
@ -661,9 +661,9 @@ gnc_reconcile_list_fill(GNCReconcileList *list)
continue;
if((account_type == STOCK) || (account_type == MUTUAL))
amount = xaccSplitGetShareAmount(split);
amount = DxaccSplitGetShareAmount(split);
else
amount = xaccSplitGetValue(split);
amount = DxaccSplitGetValue(split);
if ((amount < 0) && (list->list_type == RECLIST_DEBIT))
continue;
@ -677,7 +677,8 @@ gnc_reconcile_list_fill(GNCReconcileList *list)
strings[0] = gnc_print_date(ts);
strings[1] = xaccTransGetNum(trans);
strings[2] = xaccTransGetDescription(trans);
strings[3] = xaccPrintAmount(DABS(amount), flags, currency);
strings[3] = DxaccPrintAmount(DABS(amount), flags,
gnc_commodity_get_mnemonic(currency));
reconciled = g_hash_table_lookup(list->reconciled, split) != NULL;
recn = reconciled ? YREC : recn;

View File

@ -47,7 +47,6 @@
#include "account-tree.h"
#include "dialog-transfer.h"
#include "dialog-account.h"
#include "dialog-qif-import.h"
#include "dialog-fincalc.h"
#include "dialog-find-transactions.h"
#include "dialog-totd.h"
@ -56,7 +55,13 @@
#include "EuroUtils.h"
#include "Scrub.h"
#include "util.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
#include "gtkselect.h"
/* FIXME get rid of these */
#include <g-wrap.h>
#include "gnc.h"
/* Main Window information structure */
typedef struct _GNCMainInfo GNCMainInfo;
@ -97,7 +102,7 @@ static GNCMainInfo * gnc_get_main_info(void);
* kept around for the duration of the calculation. There may, in fact
* be better ways to do this, but none occurred. */
struct _GNCCurrencyAcc {
const char *currency;
const gnc_commodity * currency;
double assets;
double profits;
};
@ -109,7 +114,7 @@ typedef struct _GNCCurrencyAcc GNCCurrencyAcc;
* currency, plus (eventually) one for the default currency
* accumulation (like the EURO). */
struct _GNCCurrencyItem {
const char *currency;
const gnc_commodity * currency;
GtkWidget *listitem;
GtkWidget *assets_label;
GtkWidget *profits_label;
@ -119,11 +124,12 @@ typedef struct _GNCCurrencyItem GNCCurrencyItem;
/* Build a single currency item.
*
* This function handles the building of a single currency item for
* the selector. It looks like the old code in the update function,
* but now only handles a single currency. */
* This function handles the building of a single currency item for the
* selector. It looks like the old code in the update function, but now
* only handles a single currency.
*/
static GNCCurrencyItem *
gnc_ui_build_currency_item(const char *currency)
gnc_ui_build_currency_item(const gnc_commodity * currency)
{
GtkWidget *label;
GtkWidget *topbox;
@ -144,7 +150,7 @@ gnc_ui_build_currency_item(const char *currency)
gtk_widget_show(hbox);
gtk_box_pack_start(GTK_BOX(topbox), hbox, FALSE, FALSE, 5);
label = gtk_label_new(currency);
label = gtk_label_new(gnc_commodity_get_mnemonic(currency));
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
gtk_widget_show(label);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
@ -190,25 +196,24 @@ gnc_ui_build_currency_item(const char *currency)
* This will search the given list, and if no accumulator is found,
* will allocate a fresh one. */
static GNCCurrencyAcc *
gnc_ui_get_currency_accumulator(GList **list, const char *currency)
gnc_ui_get_currency_accumulator(GList **list, const gnc_commodity * currency)
{
GList *current;
GNCCurrencyAcc *found;
for (current = g_list_first(*list); current;
current = g_list_next(current))
{
current = g_list_next(current)) {
found = current->data;
if (safe_strcmp(found->currency, currency) == 0)
if (gnc_commodity_equiv(currency, found->currency)) {
return found;
}
}
}
found = g_new0(GNCCurrencyAcc, 1);
found->currency = currency;
found->assets = 0.0;
found->profits = 0.0;
*list = g_list_append(*list, found);
return found;
}
@ -219,23 +224,24 @@ gnc_ui_get_currency_accumulator(GList **list, const char *currency)
*
* It looks just like the function above, with some extra stuff to get
* the item into the list. */
static GNCCurrencyItem *
gnc_ui_get_currency_item(GList **list, const char *currency, GtkWidget *holder)
gnc_ui_get_currency_item(GList **list, const gnc_commodity * currency, GtkWidget *holder)
{
GList *current;
GNCCurrencyItem *found;
for (current = g_list_first(*list); current;
current = g_list_next(current))
{
current = g_list_next(current)) {
found = current->data;
if (safe_strcmp(found->currency, currency) == 0)
if (gnc_commodity_equiv(found->currency, currency)) {
return found;
}
}
found = gnc_ui_build_currency_item(currency);
*list = g_list_append(*list, found);
current = g_list_append(NULL, found->listitem);
gtk_select_append_items(GTK_SELECT(holder), current);
@ -250,16 +256,30 @@ gnc_ui_accounts_recurse (AccountGroup *group, GList **currency_list,
AccountGroup *children;
Account *account;
int num_accounts;
int account_type;
const char *account_currency;
int account_type;
const gnc_commodity * account_currency;
const gnc_commodity * default_currency;
const gnc_commodity * euro_commodity;
const char * default_mnemonic;
GNCCurrencyAcc *currency_accum;
GNCCurrencyAcc *euro_accum = NULL;
int i;
if (euro)
euro_accum = gnc_ui_get_currency_accumulator(currency_list,
EURO_TOTAL_STR);
default_mnemonic = gnc_lookup_string_option("International",
"Default Currency",
"USD");
default_currency = gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
default_mnemonic);
if (euro) {
euro_commodity = gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
"EUR");
euro_accum = gnc_ui_get_currency_accumulator(currency_list,
euro_commodity);
}
num_accounts = xaccGroupGetNumAccounts(group);
for (i = 0; i < num_accounts; i++)
{
@ -280,7 +300,7 @@ gnc_ui_accounts_recurse (AccountGroup *group, GList **currency_list,
case MUTUAL:
case CREDIT:
case LIABILITY:
amount = xaccAccountGetBalance(account);
amount = DxaccAccountGetBalance(account);
currency_accum->assets += amount;
if(euro)
euro_accum->assets += gnc_convert_to_euro(account_currency, amount);
@ -290,7 +310,7 @@ gnc_ui_accounts_recurse (AccountGroup *group, GList **currency_list,
break;
case INCOME:
case EXPENSE:
amount = xaccAccountGetBalance(account);
amount = DxaccAccountGetBalance(account);
currency_accum->profits -= amount;
if(euro)
euro_accum->profits -= gnc_convert_to_euro(account_currency, amount);
@ -331,17 +351,20 @@ gnc_ui_refresh_statusbar (void)
AccountGroup *group;
char asset_string[256];
char profit_string[256];
const char *default_currency;
const char * default_mnemonic;
const gnc_commodity * default_currency;
GNCCurrencyAcc *currency_accum;
GNCCurrencyItem *currency_item;
GList *currency_list;
GList *current;
gboolean euro;
default_currency = gnc_lookup_string_option("International",
default_mnemonic = gnc_lookup_string_option("International",
"Default Currency",
"USD");
default_currency = gnc_commodity_table_lookup(gnc_engine_commodities(),
default_mnemonic,
GNC_COMMODITY_NS_ISO);
euro = gnc_lookup_boolean_option("International",
"Enable EURO support",
FALSE);
@ -374,13 +397,15 @@ gnc_ui_refresh_statusbar (void)
main_info->totals_combo);
currency_item->touched = 1;
xaccSPrintAmount(asset_string, currency_accum->assets,
PRTSYM | PRTSEP, currency_accum->currency);
DxaccSPrintAmount(asset_string, currency_accum->assets,
PRTSYM | PRTSEP,
gnc_commodity_get_mnemonic(currency_accum->currency));
gtk_label_set_text(GTK_LABEL(currency_item->assets_label), asset_string);
gnc_set_label_color(currency_item->assets_label, currency_accum->assets);
xaccSPrintAmount(profit_string, currency_accum->profits,
PRTSYM | PRTSEP, currency_accum->currency);
DxaccSPrintAmount(profit_string, currency_accum->profits,
PRTSYM | PRTSEP,
gnc_commodity_get_mnemonic(currency_accum->currency));
gtk_label_set_text(GTK_LABEL(currency_item->profits_label), profit_string);
gnc_set_label_color(currency_item->profits_label, currency_accum->profits);
@ -395,11 +420,11 @@ gnc_ui_refresh_statusbar (void)
while (current)
{
GList *next = current->next;
currency_item = current->data;
if (currency_item->touched == 0
&& strcmp(currency_item->currency, default_currency) != 0)
{
&& !gnc_commodity_equiv(currency_item->currency,
default_currency)) {
currency_list = g_list_append(currency_list, currency_item->listitem);
main_info->totals_list = g_list_remove_link(main_info->totals_list,
current);
@ -407,7 +432,7 @@ gnc_ui_refresh_statusbar (void)
current->data = NULL;
g_list_free_1(current);
}
current = next;
}
@ -1376,12 +1401,16 @@ mainWindow()
/* create the label containing the account balances */
{
GtkWidget *combo_box;
const char *default_currency;
const char *default_currency_mnemonic;
const gnc_commodity * default_currency;
GNCCurrencyItem *def_item;
default_currency = gnc_lookup_string_option("International",
"Default Currency",
"USD");
default_currency_mnemonic = gnc_lookup_string_option("International",
"Default Currency",
"USD");
default_currency = gnc_commodity_table_lookup(gnc_engine_commodities(),
GNC_COMMODITY_NS_ISO,
default_currency_mnemonic);
combo_box = gtk_select_new();
main_info->totals_combo = combo_box;
main_info->totals_list = NULL;
@ -1402,12 +1431,12 @@ mainWindow()
gtk_container_add(GTK_CONTAINER(scrolled_win),
GTK_WIDGET(main_info->account_tree));
/* Attach delete and destroy signals to the main window */
gtk_signal_connect (GTK_OBJECT (app), "delete_event",
GTK_SIGNAL_FUNC (gnc_ui_mainWindow_delete_cb),
NULL);
gtk_signal_connect (GTK_OBJECT (app), "destroy_event",
GTK_SIGNAL_FUNC (gnc_ui_mainWindow_destroy_event_cb),
NULL);

View File

@ -171,7 +171,7 @@ static double
recnRecalculateBalance(RecnWindow *recnData)
{
const char *amount;
const char *currency;
const gnc_commodity * currency;
double debit;
double credit;
double starting;
@ -192,12 +192,14 @@ recnRecalculateBalance(RecnWindow *recnData)
/* update the starting balance */
if (recnData->use_shares)
starting = xaccAccountGetShareReconciledBalance(recnData->account);
starting = DxaccAccountGetShareReconciledBalance(recnData->account);
else
starting = xaccAccountGetReconciledBalance(recnData->account);
starting = DxaccAccountGetReconciledBalance(recnData->account);
if (reverse_balance)
starting = -starting;
amount = xaccPrintAmount(starting, flags, currency);
amount = DxaccPrintAmount(starting, flags,
gnc_commodity_get_mnemonic(currency));
gnc_set_label_color(recnData->starting, starting);
gtk_label_set_text(GTK_LABEL(recnData->starting), amount);
if (reverse_balance)
@ -207,7 +209,8 @@ recnRecalculateBalance(RecnWindow *recnData)
ending = recnData->new_ending;
if (reverse_balance)
ending = -ending;
amount = xaccPrintAmount(ending, flags, currency);
amount = DxaccPrintAmount(ending, flags,
gnc_commodity_get_mnemonic(currency));
gnc_set_label_color(recnData->ending, ending);
gtk_label_set_text(GTK_LABEL(recnData->ending), amount);
if (reverse_balance)
@ -220,17 +223,21 @@ recnRecalculateBalance(RecnWindow *recnData)
(GNC_RECONCILE_LIST(recnData->credit));
/* Update the total debit and credit fields */
amount = xaccPrintAmount(DABS(debit), flags, currency);
amount = DxaccPrintAmount(DABS(debit), flags,
gnc_commodity_get_mnemonic(currency));
gtk_label_set_text(GTK_LABEL(recnData->total_debit), amount);
amount = xaccPrintAmount(credit, flags, currency);
amount = DxaccPrintAmount(credit, flags,
gnc_commodity_get_mnemonic(currency));
gtk_label_set_text(GTK_LABEL(recnData->total_credit), amount);
/* update the reconciled balance */
reconciled = starting + debit - credit;
if (reverse_balance)
reconciled = -reconciled;
amount = xaccPrintAmount(reconciled, flags, currency);
amount = DxaccPrintAmount(reconciled, flags,
gnc_commodity_get_mnemonic(currency));
gnc_set_label_color(recnData->reconciled, reconciled);
gtk_label_set_text(GTK_LABEL(recnData->reconciled), amount);
if (reverse_balance)
@ -240,7 +247,8 @@ recnRecalculateBalance(RecnWindow *recnData)
diff = ending - reconciled;
if (reverse_balance)
diff = -diff;
amount = xaccPrintAmount(diff, flags, currency);
amount = DxaccPrintAmount(diff, flags,
gnc_commodity_get_mnemonic(currency));
gnc_set_label_color(recnData->difference, diff);
gtk_label_set_text(GTK_LABEL(recnData->difference), amount);
if (reverse_balance)
@ -259,9 +267,9 @@ gnc_start_recn_update_cb(GtkWidget *widget, GdkEventFocus *event,
GNCPrintAmountFlags flags;
Account *account = data;
int account_type;
const char *currency;
const char *new_string;
const char *string;
const gnc_commodity * currency;
const char * new_string;
const char * string;
double value;
flags = PRTSYM | PRTSEP;
@ -269,7 +277,7 @@ gnc_start_recn_update_cb(GtkWidget *widget, GdkEventFocus *event,
string = gtk_entry_get_text(entry);
value = 0.0;
xaccParseAmount(string, TRUE, &value, NULL);
DxaccParseAmount(string, TRUE, &value, NULL);
account_type = xaccAccountGetType(account);
if ((account_type == STOCK) || (account_type == MUTUAL) ||
@ -278,7 +286,8 @@ gnc_start_recn_update_cb(GtkWidget *widget, GdkEventFocus *event,
currency = xaccAccountGetCurrency(account);
new_string = xaccPrintAmount(value, flags & ~PRTSYM, currency);
new_string = DxaccPrintAmount(value, flags & ~PRTSYM,
gnc_commodity_get_mnemonic(currency));
if (safe_strcmp(string, new_string) == 0)
return FALSE;
@ -307,9 +316,9 @@ startRecnWindow(GtkWidget *parent, Account *account,
double *new_ending, time_t *statement_date)
{
GtkWidget *dialog, *end_value, *date_value;
const gnc_commodity * currency;
GNCAccountType account_type;
GNCPrintAmountFlags flags;
const char *currency;
const char *amount;
double dendBalance;
char *title;
@ -323,10 +332,10 @@ startRecnWindow(GtkWidget *parent, Account *account,
(account_type == CURRENCY))
{
flags |= PRTSHR;
dendBalance = xaccAccountGetShareReconciledBalance(account);
dendBalance = DxaccAccountGetShareReconciledBalance(account);
}
else
dendBalance = xaccAccountGetReconciledBalance(account);
dendBalance = DxaccAccountGetReconciledBalance(account);
if (gnc_reverse_balance(account))
{
@ -336,7 +345,8 @@ startRecnWindow(GtkWidget *parent, Account *account,
currency = xaccAccountGetCurrency(account);
amount = xaccPrintAmount(dendBalance, flags, currency);
amount = DxaccPrintAmount(dendBalance, flags,
gnc_commodity_get_mnemonic(currency));
/* Create the dialog box... */
title = gnc_recn_make_window_name(account);
@ -366,7 +376,8 @@ startRecnWindow(GtkWidget *parent, Account *account,
date_value = gnc_date_edit_new(*statement_date, FALSE, FALSE);
end_value = gtk_entry_new();
amount = xaccPrintAmount(*new_ending, flags & ~PRTSYM, currency);
amount = DxaccPrintAmount(*new_ending, flags & ~PRTSYM,
gnc_commodity_get_mnemonic(currency));
gtk_entry_set_text(GTK_ENTRY(end_value), amount);
gtk_editable_select_region(GTK_EDITABLE(end_value), 0, -1);
@ -414,7 +425,8 @@ startRecnWindow(GtkWidget *parent, Account *account,
string = gtk_entry_get_text(GTK_ENTRY(end_value));
*new_ending = 0.0;
xaccParseAmount(string, TRUE, new_ending, NULL);
DxaccParseAmount(string, TRUE, new_ending, NULL);
*statement_date = gnc_date_edit_get_date(GNC_DATE_EDIT(date_value));
if (gnc_reverse_balance(account))
@ -1280,9 +1292,9 @@ recnWindow(GtkWidget *parent, Account *account)
(type == CURRENCY));
if (recnData->use_shares)
new_ending = xaccAccountGetShareBalance(account);
new_ending = DxaccAccountGetShareBalance(account);
else
new_ending = xaccAccountGetBalance(account);
new_ending = DxaccAccountGetBalance(account);
/* The last time reconciliation was attempted during the current
* execution of gnucash, the date was stored. Use that date if
@ -1614,7 +1626,7 @@ find_payment_account(Account *account)
continue;
/* ignore 'purchases' */
if (xaccSplitGetShareAmount(split) <= 0.0)
if (DxaccSplitGetShareAmount(split) <= 0.0)
continue;
trans = xaccSplitGetParent(split);

View File

@ -548,7 +548,8 @@ gnc_register_set_date_range(RegWindow *regData)
start = gnc_register_min_day_time(start);
xaccQueryAddDateMatchTT(regData->ledger->query,
start, LONG_MAX,
TRUE, start,
FALSE, 0,
QUERY_AND);
}
@ -560,8 +561,8 @@ gnc_register_set_date_range(RegWindow *regData)
end = gnc_register_max_day_time(end);
xaccQueryAddDateMatchTT(regData->ledger->query,
LONG_MIN,
end,
FALSE, 0,
TRUE, end,
QUERY_AND);
}
@ -1051,7 +1052,7 @@ print_check_cb(GtkWidget * widget, gpointer data)
gh_procedure_p(print_check))
{
payee = xaccTransGetDescription(trans);
amount = xaccSplitGetValue(split);
amount = DxaccSplitGetValue(split);
date = xaccTransGetDate(trans);
memo = xaccSplitGetMemo(split);
@ -1761,13 +1762,12 @@ regRefresh(xaccLedgerDisplay *ledger)
gboolean euro = gnc_lookup_boolean_option("International",
"Enable EURO support",
FALSE);
const char *currency = xaccAccountGetCurrency(ledger->leader);
const gnc_commodity * currency = xaccAccountGetCurrency(ledger->leader);
/* no EURO converson, if account is already EURO or no EURO currency */
if(currency != NULL)
{
euro = (euro && strncasecmp("EUR", currency, 3) &&
gnc_is_euro_currency(currency));
euro = (euro && gnc_is_euro_currency(currency));
}
else
{
@ -1788,11 +1788,12 @@ regRefresh(xaccLedgerDisplay *ledger)
if (reverse)
amount = -amount;
xaccSPrintAmount(string, amount, print_flags, currency);
DxaccSPrintAmount(string, amount, print_flags,
gnc_commodity_get_mnemonic(currency));
if(euro)
{
strcat(string, " / ");
xaccSPrintAmount(string + strlen(string),
DxaccSPrintAmount(string + strlen(string),
gnc_convert_to_euro(currency, amount),
print_flags | PRTEUR, NULL);
}
@ -1808,11 +1809,12 @@ regRefresh(xaccLedgerDisplay *ledger)
if (reverse)
amount = -amount;
xaccSPrintAmount(string, amount, print_flags, currency);
DxaccSPrintAmount(string, amount, print_flags,
gnc_commodity_get_mnemonic(currency));
if(euro)
{
strcat(string, " / ");
xaccSPrintAmount(string + strlen(string),
DxaccSPrintAmount(string + strlen(string),
gnc_convert_to_euro(currency, amount),
print_flags | PRTEUR, NULL);
}

View File

@ -1,5 +1,5 @@
SUBDIRS = swig
#SUBDIRS = swig
EXTRA_DIST = \
.cvsignore

View File

@ -33,14 +33,12 @@ INCLUDES = \
libgncswig_la_LIBADD = \
@GLIB_LIBS@ \
${top_srcdir}/src/engine/AccInfo.lo \
${top_srcdir}/src/engine/Account.lo \
${top_srcdir}/src/engine/DateUtils.lo \
${top_srcdir}/src/engine/FileIO.lo \
${top_srcdir}/src/engine/GNCId.lo \
${top_srcdir}/src/engine/Group.lo \
${top_srcdir}/src/engine/Query.lo \
${top_srcdir}/src/engine/Queue.lo \
${top_srcdir}/src/engine/Scrub.lo \
${top_srcdir}/src/engine/Session.lo \
${top_srcdir}/src/engine/TransLog.lo \
@ -52,14 +50,12 @@ libgncswig_la_LIBADD = \
${top_srcdir}/src/engine/md5.lo
SWIG_INPUT_HDRS := \
${top_srcdir}/src/engine/AccInfo.h \
${top_srcdir}/src/engine/Account.h \
${top_srcdir}/src/engine/DateUtils.h \
${top_srcdir}/src/engine/FileIO.h \
${top_srcdir}/src/engine/GNCId.h \
${top_srcdir}/src/engine/Group.h \
${top_srcdir}/src/engine/Query.h \
${top_srcdir}/src/engine/Queue.h \
${top_srcdir}/src/engine/Scrub.h \
${top_srcdir}/src/engine/Session.h \
${top_srcdir}/src/engine/TransLog.h \

View File

@ -598,6 +598,7 @@ gnucash_sheet_row_get_distance (GnucashSheet *sheet, int v_row_a, int v_row_b)
return sign * distance;
}
#if 0
static gint
gnucash_sheet_col_get_distance (GnucashSheet *sheet, int vrow,
int v_col_a, int v_col_b)
@ -642,7 +643,7 @@ gnucash_sheet_col_get_distance (GnucashSheet *sheet, int vrow,
return sign * distance;
}
#endif
void
gnucash_sheet_redraw_all (GnucashSheet *sheet)

View File

@ -119,7 +119,6 @@ PriceMV (BasicCell *_cell,
thousands_sep = lc->mon_thousands_sep[0];
else
thousands_sep = lc->thousands_sep[0];
for (i = 0; change[i] != '\0'; i++)
if (!isdigit(change[i]) &&
!isspace(change[i]) &&
@ -260,7 +259,7 @@ xaccPriceCellPrintValue (PriceCell *cell)
if (cell->is_currency)
flags |= PRTCUR;
return xaccPrintAmount(cell->amount, flags, NULL);
return DxaccPrintAmount(cell->amount, flags, NULL);
}
/* ================================================ */

View File

@ -159,7 +159,7 @@ gnc_table_init_gui (gncUIWidget widget, void *data)
name = gh_scm2newstr(gh_car (assoc), NULL);
ctype = xaccSplitRegisterGetCellTypeFromName (name);
if (name)
free(name);
free((void *)name);
if (ctype == NO_CELL)
continue;

View File

@ -36,7 +36,11 @@ gnc_regular_scm_files = \
tip-of-the-day.scm \
tip-list.scm \
utilities.scm \
xml-generator.scm
xml-generator.scm \
iso-4217-currencies.scm \
engine-init.scm \
commodity-table.scm \
commodity-import.scm
gncscm_DATA = ${gnc_autogen_scm_files} ${gnc_regular_scm_files}

View File

@ -95,9 +95,17 @@
(cons "evaluate"
(cons 'string
(lambda (val)
(set! gnc:*batch-mode-forms-to-evaluate*
(cons val gnc:*batch-mode-forms-to-evaluate*)))))
(set! gnc:*batch-mode-things-to-do*
(cons val gnc:*batch-mode-things-to-do*)))))
;; Given a string, --load will load the indicated file, if possible.
(cons "load"
(cons 'string
(lambda (val)
(set! gnc:*batch-mode-things-to-do*
(cons (lambda () (load val))
gnc:*batch-mode-things-to-do*)))))
(cons "load-user-config"
(cons 'boolean gnc:load-user-config-if-needed))

View File

@ -0,0 +1,26 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; commodity-import.scm
;;; file-io hooks to convert old-style currency strings to
;;; real gnucash commodities.
;;;
;;; Bill Gribble <grib@billgribble.com> 11 Aug 2000
;;; $Id$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(gnc:support "commodity-import.scm")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; import-old-currencies
;; If there are old currencies in the account group, start the
;; import wizard.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (import-old-currencies from-filename)
(if (gnc:commodity-table-has-namespace
(gnc:engine-commodities)
"GNC_LEGACY_CURRENCIES")
(gnc:import-legacy-commodities from-filename)))
(gnc:hook-add-dangler gnc:*file-opened-hook* import-old-currencies)

View File

@ -0,0 +1,79 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; commodity-table.scm
;;; load and save commodity tables
;;;
;;; Bill Gribble <grib@billgribble.com> 3 Aug 2000
;;; $Id$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define gnc:*iso-4217-currency-file*
(gnc:make-config-var
"Database of ISO-4217 currency definitions"
(lambda (var value) (if (string? value) (list value) #f))
string=?
"iso-4217-currencies.scm"))
(define GNC_COMMODITY_NS_ISO "ISO4217")
(define GNC_COMMODITY_NS_NASDAQ "NASDAQ")
(define GNC_COMMODITY_NS_NYSE "NYSE")
(define GNC_COMMODITY_NS_AMEX "AMEX")
(define GNC_COMMODITY_NS_EUREX "EUREX")
(define GNC_COMMODITY_NS_MUTUAL "FUND")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (gnc:setup-default-namespaces)
;; make sure there are some reasonable commodity namespaces
;; in the engine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (gnc:setup-default-namespaces)
(let ((table (gnc:engine-commodities)))
(gnc:commodity-table-add-namespace table GNC_COMMODITY_NS_AMEX)
(gnc:commodity-table-add-namespace table GNC_COMMODITY_NS_NYSE)
(gnc:commodity-table-add-namespace table GNC_COMMODITY_NS_NASDAQ)
(gnc:commodity-table-add-namespace table GNC_COMMODITY_NS_EUREX)
(gnc:commodity-table-add-namespace table GNC_COMMODITY_NS_MUTUAL)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (gnc:load-iso-4217-currencies)
;; load the default table of ISO-4217 currency information.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (gnc:load-iso-4217-currencies)
(let ((table (gnc:engine-commodities)))
(with-input-from-file
(gnc:find-in-directories
(gnc:config-var-value-get gnc:*iso-4217-currency-file*)
gnc:*load-path*)
(lambda ()
(let loop ((form (read)))
(if (not (eof-object? form))
(begin
(if (and (list? form)
(eq? 8 (length form)))
(let ((fullname (list-ref form 0))
(unitname (list-ref form 1))
(partname (list-ref form 2))
(namespace (list-ref form 3))
(mnemonic (list-ref form 4))
(exchange-code (list-ref form 5))
(parts-per-unit (list-ref form 6))
(smallest-fraction (list-ref form 7)))
(if (and (string? fullname)
(string? unitname)
(string? partname)
(string? namespace)
(string? mnemonic)
(string? exchange-code)
(number? parts-per-unit)
(number? smallest-fraction))
(let ((comm
(gnc:commodity-create
fullname namespace
mnemonic exchange-code
smallest-fraction)))
(gnc:commodity-table-insert table comm)))))
(loop (read)))))))))

11
src/scm/engine-init.scm Normal file
View File

@ -0,0 +1,11 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; engine-init.scm
;;; make sure the engine is initialized at gnucash startup
;;;
;;; Bill Gribble <grib@billgribble.com> 4 Aug 2000
;;; $Id$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; initialize commodity tables in the engine
(gnc:load-iso-4217-currencies)
(gnc:setup-default-namespaces)

View File

@ -126,7 +126,7 @@
(gnc:split-scm-get-account-guid split-scm))))
(if (and account (gnc:account-can-insert-split? account split))
(begin
(gnc:account-begin-edit account 1)
(gnc:account-begin-edit account)
(gnc:account-insert-split account split)
(gnc:account-commit-edit account)))))))
@ -136,12 +136,6 @@
(security (gnc:account-get-security account))
(trans (gnc:split-get-parent split)))
;; fixme: This is a temporary fix of a g-wrap problem.
(if (not currency)
(set! currency ""))
(if (not security)
(set! security ""))
(or (< (gnc:transaction-get-split-count trans) 2)
(gnc:transaction-is-common-currency trans currency)
(gnc:transaction-is-common-currency trans security))))

View File

@ -23,6 +23,58 @@
(gnc:support "engine-utilities.scm")
(define (gnc:filename->account-group filename)
"Returns an account group on success and #f on failure"
(let* ((session (gnc:malloc-session)))
(if (not session)
#f
(begin
(gnc:init-session session)
(let ((account-group (gnc:session-begin-file session filename)))
(if (not account-group)
(begin
(display (list 'serr (gnc:session-get-error session)))
(newline)
(gnc:session-destroy session)
#f)
(begin
(gnc:session-end session)
(gnc:session-destroy session)
account-group)))))))
(define (gnc:call-with-account-data-from-file filename proc)
;; calls proc with one argument, the account group representing the
;; data in filename. If there's an error, this procedure throws an
;; exception of type misc-error (for now). Otherwise, the return
;; value is the result of the call to proc.
;;
;; This procedure does not currently handle any acceptions thrown by
;; the sub-procedures that it calls.
(let ((account-group (gnc:filename->account-group filename)))
(if (not account-group)
(throw 'misc-error)
(let ((result (proc account-group)))
(gnc:free-account-group account-group)
result))))
; (define (gnc:account-transactions-for-each thunk account)
; ;; You must call gnc:group-reset-write-flags on the account group
; ;; before using this...
; (let loop ((num-splits (gnc:account-get-split-count account))
; (i 0))
; (if (< i num-splits)
; (let* ((split (gnc:account-get-split account i))
; (transaction (gnc:split-get-parent split)))
; ;; We don't use the flags just like FileIO does (only 1 pass here)...
; (if (= (gnc:transaction-get-write-flag transaction) 0)
; (begin
; (thunk transaction)
; (gnc:transaction-set-write-flag transaction 2)))
; (loop num-splits (+ i 1))))))
(define (gnc:transaction-map-splits thunk transaction)
(let loop ((num-splits (gnc:transaction-get-split-count transaction))
(i 0))

Some files were not shown because too many files have changed in this diff Show More