You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
905 lines
38 KiB
905 lines
38 KiB
/***************************************************************************
|
|
mymoneygncreader - description
|
|
-------------------
|
|
begin : Wed Mar 3 2004
|
|
copyright : (C) 2000-2004 by Michael Edwardes
|
|
email : mte@users.sourceforge.net
|
|
Javier Campos Morales <javi_c@users.sourceforge.net>
|
|
Felix Rodriguez <frodriguez@users.sourceforge.net>
|
|
John C <thetacoturtle@users.sourceforge.net>
|
|
Thomas Baumgart <ipwizard@users.sourceforge.net>
|
|
Kevin Tambascio <ktambascio@users.sourceforge.net>
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
/*
|
|
The main class of this module, MyMoneyGncReader, contains only a readFile()
|
|
function, which controls the import of data from an XML file created by the
|
|
current GnuCash version (1.8.8).
|
|
|
|
The XML is processed in class XmlReader, which is an implementation of the TQt
|
|
SAX2 reader class.
|
|
|
|
Data in the input file is processed as a set of objects which fortunately,
|
|
though perhaps not surprisingly, have almost a one-for-one correspondence with
|
|
KMyMoney objects. These objects are bounded by start and end XML elements, and
|
|
may contain both nested objects (described as sub objects in the code), and data
|
|
items, also delimited by start and end elements. For example:
|
|
<gnc:account> * start of sub object within file
|
|
<act:name>Account Name</act:name> * data string with start and end elements
|
|
...
|
|
</gnc:account> * end of sub objects
|
|
|
|
A GnuCash file may consist of more than one 'book', or set of data. It is not
|
|
clear how we could currently implement this, so only the first book in a file is
|
|
processed. This should satisfy most user situations.
|
|
|
|
GnuCash is somewhat inconsistent in its division of the major sections of the
|
|
file. For example, multiple price history entries are delimited by <gnc:pricedb>
|
|
elements, while each account starts with its own top-level element. In general,
|
|
the 'container' elements are ignored.
|
|
|
|
XmlReader
|
|
|
|
This is an implementation of the TQt TQXmlDefaultHandler class, which provides
|
|
three main function calls in addition to start and end of document. The
|
|
startElement() and endElement() calls are self-explanatory, the characters()
|
|
function provides data strings. Thus in the above example, the sequence of calls
|
|
would be
|
|
startElement() for gnc:account
|
|
startElement() for act:name
|
|
characters() for 'Account Name'
|
|
endElement() for act:name
|
|
...
|
|
endElement() for gnc:account
|
|
|
|
Objects
|
|
|
|
Since the processing requirements of XML for most elements are very similar, the
|
|
common code is implemented in a GncObject class, from which the others are
|
|
derived, with virtual function calls to cater for any differences. The
|
|
'grandfather' object, GncFile representing the file (or more correctly, 'book')
|
|
as a whole, is created in the startDocument() function call.
|
|
|
|
The constructor function of each object is responsible for providing two lists
|
|
for the XmlReader to scan, a list of element names which represent sub objects
|
|
(called sub elements in the code), and a similar list of names representing data
|
|
elements. In addition, an array of variables (m_v) is provided and initialized,
|
|
to contain the actual data strings.
|
|
|
|
Implementation
|
|
|
|
Since objects may be nested, a stack is used, with the top element pointing to
|
|
the 'current object'. The startDocument() call creates the first, GncFile,
|
|
object at the top of the stack.
|
|
|
|
As each startElement() call occurs, the two element lists created by the current
|
|
object are scanned.
|
|
If this element represents the start of a sub object, the current object's subEl()
|
|
function is called to create an instance of the appropriate type. This is then
|
|
pushed to the top of the stack, and the new object's initiate() function is
|
|
called. This is used to process any XML attributes attached to the element;
|
|
GnuCash makes little use of these.
|
|
If this represents the start of a data element, a pointer (m_dataPointer) is set
|
|
to point to an entry in the array (m_v) in which a subsequent characters() call
|
|
can store the actual data.
|
|
|
|
When an endElement() call occurs, a check is made to see if it matches the
|
|
element name which started the current object. If so, the object's terminate()
|
|
function is called. If the object represents a similar KMM object, this will
|
|
normally result in a call to a conversion routine in the main
|
|
(MyMoneyGncReader) class to convert the data to native format and place it in
|
|
storage. The stack is then popped, and the parent (now current) object notified
|
|
by a call to its endSubEl() function. Again depending on the type of object,
|
|
this will either delete the instance, or save it in its own storage for later
|
|
processing.
|
|
For example, a GncSplit object makes little sense outside the context of its
|
|
transaction, so will be saved by the transaction. A GncTransaction object on the
|
|
other hand will be converted, along with its attendant splits, and then deleted
|
|
by its parent.
|
|
|
|
Since at any one time an object will only be processing either a subobject or a
|
|
data element, a single object variable, m_state, is used to determine the actual
|
|
type. In effect, it acts as the current index into either the subElement or
|
|
dataElement list. As an object variable, it will be saved on the stack across
|
|
subobject processing.
|
|
|
|
Exceptions and Problems
|
|
|
|
Fatal exceptions are processed via the standard MyMoneyException method.
|
|
Due to differences in implementation between GnuCash and KMM, it is not always
|
|
possible to provide an absolutely correct conversion. When such a problem
|
|
situation is recognized, a message, along with any relevant variable data, is
|
|
passed to the main class, and used to produce a report when processing
|
|
terminates. The GncMessages and GncMessageArg classes implement this.
|
|
|
|
Anonymizer
|
|
|
|
When debugging problems, it is often useful to have a trace of what is happening
|
|
within the module. However, in view of the sensitive nature of personal finance
|
|
data, most users will be reluctant to provide this. Accordingly, an anonymize
|
|
(hide()) function is provided to handle data strings. These may either be passed
|
|
through asis (non-personal data), blanked out (non-critical but possibly personal
|
|
data), replaced with a generated version (required, but possibly personal), or
|
|
randomized (monetary amounts). The action for each data item is determined in
|
|
the object's constructor function along with the creation of the data element
|
|
list.
|
|
This module will later be used as the basis of a file anonymizer, which will
|
|
enable users to safely provide us with a copy of their GnuCash files, and will
|
|
allow us to test the structure, if not the data content, of the file.
|
|
*/
|
|
|
|
#ifndef MYMONEYSTORAGEGNC_H
|
|
#define MYMONEYSTORAGEGNC_H
|
|
|
|
// Some STL headers in GCC4.3 contain operator new. Memory checker mangles these
|
|
#ifdef _CHECK_MEMORY
|
|
#undef new
|
|
#endif
|
|
// system includes
|
|
#include <stdlib.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// TQt Includes
|
|
|
|
#include <tqdatastream.h>
|
|
class TQIODevice;
|
|
#include <tqobject.h>
|
|
#include <tqvaluelist.h>
|
|
#include <tqptrlist.h>
|
|
#include <tqptrstack.h>
|
|
#include <tqxml.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqtextcodec.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Project Includes
|
|
#ifdef _CHECK_MEMORY
|
|
#include <kmymoney/mymoneyutils.h>
|
|
#endif
|
|
|
|
#ifndef _GNCFILEANON
|
|
#include "../mymoney/storage/imymoneyserialize.h" // not used any more, but call interface requires it
|
|
#include "../mymoney/storage/imymoneystorageformat.h"
|
|
#endif // _GNCFILEANON
|
|
|
|
// not sure what these are for, but leave them in
|
|
#define VERSION_0_60_XML 0x10000010 // Version 0.5 file version info
|
|
#define VERSION_0_61_XML 0x10000011 // use 8 bytes for MyMoneyMoney objects
|
|
#define GNUCASH_ID_KEY "GNUCASH_ID"
|
|
|
|
typedef TQMap<TQString, TQString> map_accountIds;
|
|
typedef map_accountIds::iterator map_accountIds_iter;
|
|
typedef map_accountIds::const_iterator map_accountIds_citer;
|
|
|
|
typedef TQMap<TQString, TQStringList> map_elementVersions;
|
|
|
|
class MyMoneyGncReader;
|
|
|
|
/** GncObject is the base class for the various objects in the gnucash file
|
|
Beyond the first level XML objects, elements will be of one of three types:
|
|
1. Sub object elements, which require creation of another object to process
|
|
2. Data object elements, which are only followed by data to be stored in a variable (m_v array)
|
|
3. Ignored objects, data not needed and not included herein
|
|
*/
|
|
class GncObject {
|
|
public:
|
|
GncObject();
|
|
; // to save delete loop when finished
|
|
virtual ~GncObject() {} // make sure to have impl of all virtual rtns to avoid vtable errors?
|
|
protected:
|
|
friend class XmlReader;
|
|
friend class MyMoneyGncReader;
|
|
|
|
// check for sub object element; if it is, create the object
|
|
GncObject *isSubElement (const TQString &elName, const TQXmlAttributes& elAttrs);
|
|
// check for data element; if so, set data pointer
|
|
bool isDataElement (const TQString &elName, const TQXmlAttributes& elAttrs);
|
|
// process start element for 'this'; normally for attribute checking; other initialization done in constructor
|
|
virtual void initiate (const TQString&, const TQXmlAttributes&) { return ;};
|
|
// a sub object has completed; process the data it gathered
|
|
virtual void endSubEl(GncObject *) {m_dataPtr = 0; return ;};
|
|
// store data for data element
|
|
void storeData (const TQString& pData) // NB - data MAY come in chunks, and may need to be anonymized
|
|
{if (m_dataPtr != 0)
|
|
m_dataPtr->append (hide (pData, m_anonClass)); return ;}
|
|
// following is provided only for a future file anonymizer
|
|
TQString getData () const { return ((m_dataPtr != 0) ? *m_dataPtr : "");};
|
|
void resetDataPtr() {m_dataPtr = 0;};
|
|
// process end element for 'this'; usually to convert to KMM format
|
|
virtual void terminate() { return ;};
|
|
void setVersion (const TQString& v) {m_version = v; return; };
|
|
TQString version() const {return (m_version);};
|
|
|
|
// some gnucash elements have version attribute; check it
|
|
void checkVersion (const TQString&, const TQXmlAttributes&, const map_elementVersions&);
|
|
// get name of element processed by 'this'
|
|
TQString getElName () const { return (m_elementName);};
|
|
// pass 'main' pointer to object
|
|
void setPm (MyMoneyGncReader *pM) {pMain = pM;};
|
|
// debug only
|
|
void debugDump();
|
|
|
|
// called by isSubElement to create appropriate sub object
|
|
virtual GncObject *startSubEl() { return (0);};
|
|
// called by isDataElement to set variable pointer
|
|
virtual void dataEl(const TQXmlAttributes&) {m_dataPtr = m_v.at(m_state); m_anonClass = m_anonClassList[m_state];};
|
|
// return gnucash data string variable pointer
|
|
virtual TQString var (int i) const;
|
|
// anonymize data
|
|
virtual TQString hide (TQString, unsigned int);
|
|
|
|
MyMoneyGncReader *pMain; // pointer to 'main' class
|
|
// used at start of each transaction so same money hide factor is applied to all splits
|
|
void adjustHideFactor();
|
|
|
|
TQString m_elementName; // save 'this' element's name
|
|
TQString m_version; // and it's gnucash version
|
|
const TQString *m_subElementList; // list of sub object element names for 'this'
|
|
unsigned int m_subElementListCount; // count of above
|
|
const TQString *m_dataElementList; // ditto for data elements
|
|
unsigned int m_dataElementListCount;
|
|
TQString *m_dataPtr; // pointer to m_v variable for current data item
|
|
mutable TQPtrList<TQString> m_v; // storage for variable pointers
|
|
|
|
unsigned int m_state; // effectively, the index to subElementList or dataElementList, whichever is currently in use
|
|
|
|
const unsigned int *m_anonClassList;
|
|
enum anonActions {ASIS, SUPPRESS, NXTACC, NXTEQU, NXTPAY, NXTSCHD, MAYBEQ, MONEY1, MONEY2}; // anonymize actions - see hide()
|
|
unsigned int m_anonClass; // class of current data item for anonymizer
|
|
static double m_moneyHideFactor; // a per-transaction factor
|
|
};
|
|
|
|
// *****************************************************************************
|
|
// This is the 'grandfather' object representing the gnucash file as a whole
|
|
class GncFile : public GncObject {
|
|
public:
|
|
GncFile ();
|
|
~GncFile();
|
|
private:
|
|
enum iSubEls {BOOK, COUNT, CMDTY, PRICE, ACCT, TX, TEMPLATES, SCHEDULES, END_FILE_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
|
|
bool m_processingTemplates; // gnc uses same transaction element for ordinary and template tx's; this will distinguish
|
|
bool m_bookFound; // to detect multi-book files
|
|
};
|
|
// The following are 'utility' objects, which occur within several other object types
|
|
// ****************************************************************************
|
|
// commodity specification. consists of
|
|
// cmdty:space - either ISO4217 if this cmdty is a currency, or, usually, the name of a stock exchange
|
|
// cmdty:id - ISO4217 currency symbol, or 'ticker symbol'
|
|
class GncCmdtySpec : public GncObject {
|
|
public:
|
|
GncCmdtySpec ();
|
|
~GncCmdtySpec ();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
friend class GncTransaction;
|
|
bool isCurrency() const { return (*m_v.at(CMDTYSPC) == TQString("ISO4217"));};
|
|
TQString id() const { return (*m_v.at(CMDTYID));};
|
|
TQString space() const { return (*m_v.at(CMDTYSPC));};
|
|
private:
|
|
// data elements
|
|
enum CmdtySpecDataEls {CMDTYSPC, CMDTYID, END_CmdtySpec_DELS};
|
|
virtual TQString hide (TQString, unsigned int);
|
|
};
|
|
// *********************************************************************
|
|
// date; maybe one of two types, ts:date which is date/time, gdate which is date only
|
|
// we do not preserve time data (at present)
|
|
class GncDate : public GncObject {
|
|
public:
|
|
GncDate ();
|
|
~GncDate();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
friend class GncPrice;
|
|
friend class GncTransaction;
|
|
friend class GncSplit;
|
|
friend class GncSchedule;
|
|
friend class GncRecurrence;
|
|
const TQDate date() const { return (TQDate::fromString(m_v.at(TSDATE)->section(' ', 0, 0), TQt::ISODate));};
|
|
private:
|
|
// data elements
|
|
enum DateDataEls {TSDATE, GDATE, END_Date_DELS};
|
|
virtual void dataEl(const TQXmlAttributes&) {m_dataPtr = m_v.at(TSDATE); m_anonClass = GncObject::ASIS;}
|
|
; // treat both date types the same
|
|
};
|
|
// ************* GncKvp********************************************
|
|
// Key/value pairs, which are introduced by the 'slot' element
|
|
// Consist of slot:key (the 'name' of the kvp), and slot:value (the data value)
|
|
// the slot value also contains a slot type (string, integer, etc) implemented as an XML attribute
|
|
// kvp's may be nested
|
|
class GncKvp : public GncObject {
|
|
public:
|
|
GncKvp ();
|
|
~GncKvp();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
|
|
TQString key() const { return (var(KEY));};
|
|
TQString value() const { return (var(VALUE));};
|
|
TQString type() const { return (m_kvpType);};
|
|
unsigned int kvpCount() const { return (m_kvpList.count());};
|
|
const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum KvpSubEls {KVP, END_Kvp_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum KvpDataEls {KEY, VALUE, END_Kvp_DELS };
|
|
virtual void dataEl (const TQXmlAttributes&);
|
|
mutable TQPtrList<GncObject> m_kvpList;
|
|
TQString m_kvpType; // type is an XML attribute
|
|
};
|
|
// ************* GncLot********************************************
|
|
// KMM doesn't have support for lots as yet
|
|
class GncLot : public GncObject {
|
|
public:
|
|
GncLot ();
|
|
~GncLot();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
private:
|
|
};
|
|
|
|
/** Following are the main objects within the gnucash file, which correspond largely one-for-one
|
|
with similar objects in the kmymoney structure, apart from schedules which gnc splits between
|
|
template (transaction data) and schedule (date data)
|
|
*/
|
|
//********************************************************************
|
|
class GncCountData : public GncObject {
|
|
public:
|
|
GncCountData ();
|
|
~GncCountData ();
|
|
private:
|
|
virtual void initiate (const TQString&, const TQXmlAttributes&);
|
|
virtual void terminate();
|
|
TQString m_countType; // type of element being counted
|
|
};
|
|
//********************************************************************
|
|
class GncCommodity : public GncObject {
|
|
public:
|
|
GncCommodity ();
|
|
~GncCommodity();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
bool isCurrency() const { return (var(SPACE) == TQString("ISO4217"));};
|
|
TQString space() const { return (var(SPACE));};
|
|
TQString id() const { return (var(ID));};
|
|
TQString name() const { return (var(NAME));};
|
|
TQString fraction() const { return (var(FRACTION));};
|
|
private:
|
|
virtual void terminate();
|
|
// data elements
|
|
enum {SPACE, ID, NAME, FRACTION, END_Commodity_DELS};
|
|
};
|
|
// ************* GncPrice********************************************
|
|
class GncPrice : public GncObject {
|
|
public:
|
|
GncPrice ();
|
|
~GncPrice();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
const GncCmdtySpec *commodity() const { return (m_vpCommodity);};
|
|
const GncCmdtySpec *currency() const { return (m_vpCurrency);};
|
|
TQString value() const { return (var(VALUE));};
|
|
TQDate priceDate () const { return (m_vpPriceDate->date());};
|
|
private:
|
|
virtual void terminate();
|
|
// sub object elements
|
|
enum PriceSubEls {CMDTY, CURR, PRICEDATE, END_Price_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum PriceDataEls {VALUE, END_Price_DELS };
|
|
GncCmdtySpec *m_vpCommodity, *m_vpCurrency;
|
|
GncDate *m_vpPriceDate;
|
|
};
|
|
// ************* GncAccount********************************************
|
|
class GncAccount : public GncObject {
|
|
public:
|
|
GncAccount ();
|
|
~GncAccount();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
GncCmdtySpec *commodity() const { return (m_vpCommodity);};
|
|
TQString id () const { return (var(ID));};
|
|
TQString name () const { return (var(NAME));};
|
|
TQString desc () const { return (var(DESC));};
|
|
TQString type () const { return (var(TYPE));};
|
|
TQString parent () const { return (var(PARENT));};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum AccountSubEls {CMDTY, KVP, LOTS, END_Account_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
virtual void terminate();
|
|
// data elements
|
|
enum AccountDataEls {ID, NAME, DESC, TYPE, PARENT, END_Account_DELS };
|
|
GncCmdtySpec *m_vpCommodity;
|
|
TQPtrList<GncObject> m_kvpList;
|
|
};
|
|
// ************* GncSplit********************************************
|
|
class GncSplit : public GncObject {
|
|
public:
|
|
GncSplit ();
|
|
~GncSplit();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
TQString id() const { return (var(ID));};
|
|
TQString memo() const { return (var(MEMO));};
|
|
TQString recon() const { return (var(RECON));};
|
|
TQString value() const { return (var(VALUE));};
|
|
TQString qty() const { return (var(TQTY));};
|
|
TQString acct() const { return (var(ACCT));};
|
|
const TQDate reconDate() const {TQDate x = TQDate(); return (m_vpDateReconciled == NULL ? x : m_vpDateReconciled->date());};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum TransactionSubEls {RECDATE, END_Split_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum SplitDataEls {ID, MEMO, RECON, VALUE, TQTY, ACCT, END_Split_DELS };
|
|
GncDate *m_vpDateReconciled;
|
|
};
|
|
// ************* GncTransaction********************************************
|
|
class GncTransaction : public GncObject {
|
|
public:
|
|
GncTransaction (bool processingTemplates);
|
|
~GncTransaction();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
TQString id() const { return (var(ID));};
|
|
TQString no() const { return (var(NO));};
|
|
TQString desc() const { return (var(DESC));};
|
|
TQString currency() const { return (m_vpCurrency == NULL ? TQString () : m_vpCurrency->id());};
|
|
TQDate dateEntered() const { return (m_vpDateEntered->date());};
|
|
TQDate datePosted() const { return (m_vpDatePosted->date());};
|
|
bool isTemplate() const { return (m_template);};
|
|
unsigned int splitCount() const { return (m_splitList.count());};
|
|
unsigned int kvpCount() const { return (m_kvpList.count());};
|
|
const GncObject *getSplit (unsigned int i) const { return (m_splitList.at(i));};
|
|
const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum TransactionSubEls {CURRCY, POSTED, ENTERED, SPLIT, KVP, END_Transaction_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
virtual void terminate();
|
|
// data elements
|
|
enum TransactionDataEls {ID, NO, DESC, END_Transaction_DELS };
|
|
GncCmdtySpec *m_vpCurrency;
|
|
GncDate *m_vpDateEntered, *m_vpDatePosted;
|
|
mutable TQPtrList<GncObject> m_splitList;
|
|
bool m_template; // true if this is a template for scheduled transaction
|
|
mutable TQPtrList<GncObject> m_kvpList;
|
|
};
|
|
|
|
// ************* GncTemplateSplit********************************************
|
|
class GncTemplateSplit : public GncObject {
|
|
public:
|
|
GncTemplateSplit ();
|
|
~GncTemplateSplit();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
TQString id() const { return (var(ID));};
|
|
TQString memo() const { return (var(MEMO));};
|
|
TQString recon() const { return (var(RECON));};
|
|
TQString value() const { return (var(VALUE));};
|
|
TQString qty() const { return (var(TQTY));};
|
|
TQString acct() const { return (var(ACCT));};
|
|
unsigned int kvpCount() const { return (m_kvpList.count());};
|
|
const GncKvp *getKvp(unsigned int i) const { return (static_cast<GncKvp *>(m_kvpList.at(i)));};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum TemplateSplitSubEls {KVP, END_TemplateSplit_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum TemplateSplitDataEls {ID, MEMO, RECON, VALUE, TQTY, ACCT, END_TemplateSplit_DELS };
|
|
mutable TQPtrList<GncObject> m_kvpList;
|
|
};
|
|
// ************* GncSchedule********************************************
|
|
class GncFreqSpec;
|
|
class GncRecurrence;
|
|
class GncSchedDef;
|
|
class GncSchedule : public GncObject {
|
|
public:
|
|
GncSchedule ();
|
|
~GncSchedule();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
TQString name() const { return (var(NAME));};
|
|
TQString enabled() const {return var(ENABLED);};
|
|
TQString autoCreate() const { return (var(AUTOC));};
|
|
TQString autoCrNotify() const { return (var(AUTOCN));};
|
|
TQString autoCrDays() const { return (var(AUTOCD));};
|
|
TQString advCrDays() const { return (var(ADVCD));};
|
|
TQString advCrRemindDays() const { return (var(ADVRD));};
|
|
TQString instanceCount() const { return (var(INSTC));};
|
|
TQString numOccurs() const { return (var(NUMOCC));};
|
|
TQString remOccurs() const { return (var(REMOCC));};
|
|
TQString templId() const { return (var(TEMPLID));};
|
|
TQDate startDate () const
|
|
{TQDate x = TQDate(); return (m_vpStartDate == NULL ? x : m_vpStartDate->date());};
|
|
TQDate lastDate () const
|
|
{TQDate x = TQDate(); return (m_vpLastDate == NULL ? x : m_vpLastDate->date());};
|
|
TQDate endDate() const
|
|
{TQDate x = TQDate(); return (m_vpEndDate == NULL ? x : m_vpEndDate->date());};
|
|
const GncFreqSpec *getFreqSpec() const { return (m_vpFreqSpec);};
|
|
const GncSchedDef *getSchedDef() const { return (m_vpSchedDef);};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum ScheduleSubEls {STARTDATE, LASTDATE, ENDDATE, FREQ, RECURRENCE, DEFINST, END_Schedule_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
virtual void terminate();
|
|
// data elements
|
|
enum ScheduleDataEls {NAME, ENABLED, AUTOC, AUTOCN, AUTOCD, ADVCD, ADVRD, INSTC,
|
|
NUMOCC, REMOCC, TEMPLID, END_Schedule_DELS };
|
|
GncDate *m_vpStartDate, *m_vpLastDate, *m_vpEndDate;
|
|
GncFreqSpec *m_vpFreqSpec;
|
|
mutable TQPtrList<GncRecurrence> m_vpRecurrence; // gnc handles multiple occurrences
|
|
GncSchedDef *m_vpSchedDef;
|
|
};
|
|
// ************* GncFreqSpec********************************************
|
|
class GncFreqSpec : public GncObject {
|
|
public:
|
|
GncFreqSpec ();
|
|
~GncFreqSpec();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values (only interval type used at present)
|
|
TQString intervalType() const { return (var(INTVT));};
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum FreqSpecSubEls {COMPO, END_FreqSpec_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum FreqSpecDataEls {INTVT, MONTHLY, DAILY, WEEKLY, INTVI, INTVO, INTVD, END_FreqSpec_DELS};
|
|
virtual void terminate();
|
|
mutable TQPtrList<GncObject> m_fsList;
|
|
};
|
|
|
|
// ************* GncRecurrence********************************************
|
|
// this object replaces GncFreqSpec from Gnucash 2.2 onwards
|
|
class GncRecurrence : public GncObject {
|
|
public:
|
|
GncRecurrence ();
|
|
~GncRecurrence();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
// access data values
|
|
TQDate startDate () const
|
|
{TQDate x = TQDate(); return (m_vpStartDate == NULL ? x : m_vpStartDate->date());};
|
|
TQString mult() const {return (var(MULT));};
|
|
TQString periodType() const {return (var(PERIODTYPE));};
|
|
TQString getFrequency() const;
|
|
private:
|
|
// subsidiary objects/elements
|
|
enum RecurrenceSubEls {STARTDATE, END_Recurrence_SELS };
|
|
virtual GncObject *startSubEl();
|
|
virtual void endSubEl(GncObject *);
|
|
// data elements
|
|
enum RecurrenceDataEls {MULT, PERIODTYPE, END_Recurrence_DELS};
|
|
virtual void terminate();
|
|
GncDate *m_vpStartDate;
|
|
};
|
|
|
|
// ************* GncSchedDef********************************************
|
|
// This is a sub-object of GncSchedule, (sx:deferredInstance) function currently unknown
|
|
class GncSchedDef : public GncObject {
|
|
public:
|
|
GncSchedDef ();
|
|
~GncSchedDef();
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
private:
|
|
// subsidiary objects/elements
|
|
};
|
|
|
|
// ****************************************************************************************
|
|
/**
|
|
XML Reader
|
|
The XML reader is an implementation of the TQt SAX2 XML parser. It determines the type
|
|
of object represented by the XMl, and calls the appropriate object functions
|
|
*/
|
|
// *****************************************************************************************
|
|
class XmlReader : public TQXmlDefaultHandler {
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
XmlReader (MyMoneyGncReader *pM) : pMain(pM) {} // keep pointer to 'main'
|
|
void processFile (TQIODevice*); // main entry point of reader
|
|
// define xml content handler functions
|
|
bool startDocument ();
|
|
bool startElement (const TQString&, const TQString&, const TQString&, const TQXmlAttributes&);
|
|
bool endElement (const TQString&, const TQString&, const TQString&);
|
|
bool characters (const TQString &);
|
|
bool endDocument();
|
|
private:
|
|
TQXmlInputSource *m_source;
|
|
TQXmlSimpleReader *m_reader;
|
|
TQPtrStack<GncObject> m_os; // stack of sub objects
|
|
GncObject *m_co; // current object, for ease of coding (=== m_os.top)
|
|
MyMoneyGncReader *pMain; // the 'main' pointer, to pass on to objects
|
|
bool m_headerFound; // check for gnc-v2 header
|
|
#ifdef _GNCFILEANON
|
|
int lastType; // 0 = start element, 1 = data, 2 = end element
|
|
int indentCount;
|
|
#endif // _GNCFILEANON
|
|
};
|
|
|
|
/**
|
|
* private classes to define messages to be held in list for final report
|
|
*/
|
|
class GncMessageArgs {
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
TQString source; // 'type of message
|
|
unsigned int code; // to identify actual message
|
|
TQValueList<TQString> args; // variable arguments
|
|
};
|
|
|
|
class GncMessages {
|
|
protected:
|
|
friend class MyMoneyGncReader;
|
|
static TQString text (const TQString, const unsigned int); // returns text of identified message
|
|
static unsigned int argCount (const TQString, const unsigned int); // returns no. of args required
|
|
private:
|
|
typedef struct {
|
|
const TQString source;
|
|
const unsigned int code;
|
|
TQString text;
|
|
}
|
|
messText;
|
|
static messText texts [];
|
|
};
|
|
|
|
/**
|
|
MyMoneyGncReader - Main class for this module
|
|
Controls overall operation of the importer
|
|
*/
|
|
|
|
#ifndef _GNCFILEANON
|
|
class MyMoneyGncReader : public IMyMoneyStorageFormat {
|
|
#else
|
|
class MyMoneyGncReader {
|
|
#endif // _GNCFILEANON
|
|
public:
|
|
MyMoneyGncReader();
|
|
virtual ~MyMoneyGncReader();
|
|
/**
|
|
* Import a GnuCash XML file
|
|
*
|
|
* @param pDevice : pointer to GnuCash file
|
|
* @param storage : pointer to MyMoneySerialize storage
|
|
*
|
|
* @return void
|
|
*
|
|
*/
|
|
#ifndef _GNCFILEANON
|
|
void readFile (TQIODevice* pDevice, IMyMoneySerialize* storage); // main entry point, IODevice is gnucash file
|
|
void writeFile (TQIODevice*, IMyMoneySerialize*) { return ;}; // dummy entry needed by kmymoneywiew. we will not be writing
|
|
#else
|
|
void readFile (TQString, TQString);
|
|
#endif // _GNCFILEANON
|
|
TQTextCodec *m_decoder;
|
|
protected:
|
|
friend class GncObject; // pity we can't just say GncObject. And compiler doesn't like multiple friends on one line...
|
|
friend class GncFile; // there must be a better way...
|
|
friend class GncDate;
|
|
friend class GncCmdtySpec;
|
|
friend class GncKvp;
|
|
friend class GncLot;
|
|
friend class GncCountData;
|
|
friend class GncCommodity;
|
|
friend class GncPrice;
|
|
friend class GncAccount;
|
|
friend class GncTransaction;
|
|
friend class GncSplit;
|
|
friend class GncTemplateTransaction;
|
|
friend class GncTemplateSplit;
|
|
friend class GncSchedule;
|
|
friend class GncFreqSpec;
|
|
friend class GncRecurrence;
|
|
friend class XmlReader;
|
|
#ifndef _GNCFILEANON
|
|
/** functions to convert gnc objects to our equivalent */
|
|
void convertCommodity (const GncCommodity *);
|
|
void convertPrice (const GncPrice *);
|
|
void convertAccount (const GncAccount *);
|
|
void convertTransaction (const GncTransaction *);
|
|
void convertSplit (const GncSplit *);
|
|
void saveTemplateTransaction (GncTransaction *t) {m_templateList.append (t);};
|
|
void convertSchedule (const GncSchedule *);
|
|
void convertFreqSpec (const GncFreqSpec *);
|
|
void convertRecurrence (const GncRecurrence *);
|
|
#else
|
|
/** functions to convert gnc objects to our equivalent */
|
|
void convertCommodity (const GncCommodity *) {return;};
|
|
void convertPrice (const GncPrice *) {return;};
|
|
void convertAccount (const GncAccount *) {return;};
|
|
void convertTransaction (const GncTransaction *) {return;};
|
|
void convertSplit (const GncSplit *) {return;};
|
|
void saveTemplateTransaction (GncTransaction *t) {return;};
|
|
void convertSchedule (const GncSchedule *) {return;};
|
|
void convertFreqSpec (const GncFreqSpec *) {return;};
|
|
#endif // _GNCFILEANON
|
|
/** to post messages for final report */
|
|
void postMessage (const TQString&, const unsigned int, const char *);
|
|
void postMessage (const TQString&, const unsigned int, const char *, const char *);
|
|
void postMessage (const TQString&, const unsigned int, const char *, const char *, const char *);
|
|
void postMessage (const TQString&, const unsigned int, const TQStringList&);
|
|
void setProgressCallback (void(*callback)(int, int, const TQString&));
|
|
void signalProgress (int current, int total, const TQString& = "");
|
|
/** user options */
|
|
/**
|
|
Scheduled Transactions
|
|
Due to differences in implementation, it is not always possible to import scheduled
|
|
transactions correctly. Though best efforts are made, it may be that some
|
|
imported transactions cause problems within kmymoney.
|
|
An attempt is made within the importer to identify potential problem transactions,
|
|
and setting this option will cause them to be dropped from the file.
|
|
A report of which were dropped, and why, will be produced.
|
|
m_dropSuspectSchedules - drop suspect scheduled transactions
|
|
*/
|
|
bool m_dropSuspectSchedules;
|
|
/**
|
|
Investments
|
|
In kmymoney, all accounts representing investments (stocks, shares, bonds, etc.) must
|
|
have an associated investment account (e.g. a broker account). The stock account holds
|
|
the share balance, the investment account a money balance.
|
|
Gnucash does not do this, so we cannot automate this function. If you have investments,
|
|
you must select one of the following options.
|
|
0 - create a separate investment account for each stock with the same name as the stock
|
|
1 - create a single investment account to hold all stocks - you will be asked for a name
|
|
2 - create multiple investment accounts - you will be asked for a name for each stock
|
|
N.B. :- option 2 doesn't really work quite as desired at present
|
|
*/
|
|
unsigned int m_investmentOption;
|
|
/** Online quotes
|
|
The user has the option to use the Finance::Quote system, as used by GnuCash, to
|
|
retrieve online share price quotes
|
|
*/
|
|
bool m_useFinanceQuote;
|
|
/** Tx Notes handling
|
|
Under some usage conditions, non-split GnuCash transactions may contain residual, usually incorrect, memo
|
|
data which is not normally visible to the user. When imported into KMyMoney however, due to display
|
|
differences, this data can become visible. Often, these transactions will have a Notes field describing
|
|
the real purpose of the transaction. If this option is selected, these notes, if present, will be used to
|
|
override the extraneous memo data." */
|
|
bool m_useTxNotes;
|
|
// set gnucash counts (not always accurate!)
|
|
void setGncCommodityCount(int i) { m_gncCommodityCount = i;};
|
|
void setGncAccountCount (int i) { m_gncAccountCount = i;};
|
|
void setGncTransactionCount (int i) { m_gncTransactionCount = i;};
|
|
void setGncScheduleCount (int i) { m_gncScheduleCount = i;};
|
|
void setSmallBusinessFound (bool b) { m_smallBusinessFound = b;};
|
|
void setBudgetsFound (bool b) { m_budgetsFound = b;};
|
|
void setLotsFound (bool b) { m_lotsFound = b;};
|
|
/* Debug Options
|
|
If you don't know what these are, best leave them alone.
|
|
gncdebug - produce general debug messages
|
|
xmldebug - produce a trace of the gnucash file XML
|
|
bAnonymize - hide personal data (account names, payees, etc., randomize money amounts)
|
|
*/
|
|
bool gncdebug; // general debug messages
|
|
bool xmldebug; // xml trace
|
|
bool bAnonymize; // anonymize input
|
|
static double m_fileHideFactor; // an overall anonymization factor to be applied to all items
|
|
bool developerDebug;
|
|
private:
|
|
void setOptions (); // to set user options from dialog
|
|
void setFileHideFactor ();
|
|
// the following handles the gnucash indicator for a bad value (-1/0) which causes us probs
|
|
TQString convBadValue (TQString gncValue) const {return (gncValue == "-1/0" ? "0/1" : gncValue); };
|
|
#ifndef _GNCFILEANON
|
|
MyMoneyTransaction convertTemplateTransaction (const TQString&, const GncTransaction *);
|
|
void convertTemplateSplit (const TQString&, const GncTemplateSplit *);
|
|
#endif // _GNCFILEANON
|
|
// wind up when all done
|
|
void terminate();
|
|
TQString buildReportSection (const TQString&);
|
|
bool writeReportToFile (const TQValueList<TQString>&);
|
|
// main storage
|
|
#ifndef _GNCFILEANON
|
|
IMyMoneyStorage *m_storage;
|
|
#else
|
|
TQTextStream oStream;
|
|
#endif // _GNCFILEANON
|
|
XmlReader *m_xr;
|
|
/** to hold the callback pointer for the progress bar */
|
|
void (*m_progressCallback)(int, int, const TQString&);
|
|
// a map of which versions of the various elements (objects) we can import
|
|
map_elementVersions m_versionList;
|
|
// counters holding count data from the Gnc 'count-data' section
|
|
int m_gncCommodityCount;
|
|
int m_gncAccountCount;
|
|
int m_gncTransactionCount;
|
|
int m_gncScheduleCount;
|
|
|
|
// flags indicating detection of features not (yet?) supported
|
|
bool m_smallBusinessFound;
|
|
bool m_budgetsFound;
|
|
bool m_lotsFound;
|
|
|
|
/** counters for reporting */
|
|
int m_commodityCount;
|
|
int m_priceCount;
|
|
int m_accountCount;
|
|
int m_transactionCount;
|
|
int m_templateCount;
|
|
int m_scheduleCount;
|
|
#ifndef _GNCFILEANON
|
|
// counters for error reporting
|
|
int m_ccCount, m_orCount, m_scCount;
|
|
// currency counter
|
|
TQMap<TQString, unsigned int> m_currencyCount;
|
|
/**
|
|
* Map gnucash vs. Kmm ids for accounts, equities, schedules, price sources
|
|
*/
|
|
TQMap<TQString, TQString> m_mapIds;
|
|
TQString m_rootId; // save the root id for terminate()
|
|
TQMap<TQString, TQString> m_mapEquities;
|
|
TQMap<TQString, TQString> m_mapSchedules;
|
|
TQMap<TQString, TQString> m_mapSources;
|
|
/**
|
|
* A list of stock accounts (gnc ids) which will be held till the end
|
|
so we can implement the user's investment option
|
|
*/
|
|
TQValueList<TQString> m_stockList;
|
|
/**
|
|
* Temporary storage areas for transaction processing
|
|
*/
|
|
TQString m_txCommodity; // save commodity for current transaction
|
|
TQString m_txPayeeId; // gnc has payee at tx level, we need it at split level
|
|
TQDate m_txDatePosted; // ditto for post date
|
|
TQString m_txChequeNo; // ditto for cheque number
|
|
/** In kmm, the order of splits is critical to some operations. These
|
|
* areas will hold the splits until we've read them all */
|
|
TQValueList<MyMoneySplit> m_splitList, m_liabilitySplitList, m_otherSplitList;
|
|
bool m_potentialTransfer; // to determine whether this might be a transfer
|
|
/** Schedules are processed through 3 different functions, any of which may set this flag */
|
|
bool m_suspectSchedule;
|
|
/**
|
|
* A holding area for template txs while we're waiting for the schedules
|
|
*/
|
|
TQPtrList<GncTransaction> m_templateList;
|
|
/** Hold a list of suspect schedule ids for later processing? */
|
|
TQValueList<TQString> m_suspectList;
|
|
/**
|
|
* To hold message data till final report
|
|
*/
|
|
TQPtrList<GncMessageArgs> m_messageList;
|
|
GncMessages *m_messageTexts;
|
|
/**
|
|
* Internal utility functions
|
|
*/
|
|
TQString createPayee (const TQString&); // create a payee and return it's id
|
|
TQString createOrphanAccount (const TQString&); // create unknown account and return the id
|
|
TQDate incrDate (TQDate lastDate, unsigned char interval, unsigned int intervalCount); // for date calculations
|
|
MyMoneyAccount checkConsistency (MyMoneyAccount& parent, MyMoneyAccount& child); // gnucash is sometimes TOO flexible
|
|
void checkInvestmentOption (TQString stockId); // implement user investment option
|
|
void getPriceSource (MyMoneySecurity stock, TQString gncSource);
|
|
#endif // _GNCFILEANON
|
|
};
|
|
|
|
#endif // MYMONEYSTORAGEGNC_H
|