summaryrefslogtreecommitdiffstats
path: root/kmymoney2/mymoney/storage/mymoneystoragexml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmymoney2/mymoney/storage/mymoneystoragexml.cpp')
-rw-r--r--kmymoney2/mymoney/storage/mymoneystoragexml.cpp908
1 files changed, 908 insertions, 0 deletions
diff --git a/kmymoney2/mymoney/storage/mymoneystoragexml.cpp b/kmymoney2/mymoney/storage/mymoneystoragexml.cpp
new file mode 100644
index 0000000..e8027d1
--- /dev/null
+++ b/kmymoney2/mymoney/storage/mymoneystoragexml.cpp
@@ -0,0 +1,908 @@
+/***************************************************************************
+ mymoneystoragexml.cpp - description
+ -------------------
+ begin : Thu Oct 24 2002
+ copyright : (C) 2002 by Kevin Tambascio
+ (C) 2004 by Thomas Baumgart
+ email : 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. *
+ * *
+ ***************************************************************************/
+
+#include "config.h"
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qdom.h>
+#include <qmap.h>
+#include <qxml.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include "kdecompat.h"
+#include <klocale.h>
+#include <kdebug.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneystoragexml.h"
+#include "../mymoneyreport.h"
+#include "../mymoneybudget.h"
+#include "../mymoneyinstitution.h"
+
+unsigned int MyMoneyStorageXML::fileVersionRead = 0;
+unsigned int MyMoneyStorageXML::fileVersionWrite = 0;
+
+
+class MyMoneyStorageXML::Private
+{
+ friend class MyMoneyStorageXML;
+public:
+ Private() {}
+
+ QMap<QString, MyMoneyInstitution> iList;
+ QMap<QString, MyMoneyAccount> aList;
+ QMap<QString, MyMoneyTransaction> tList;
+ QMap<QString, MyMoneyPayee> pList;
+ QMap<QString, MyMoneySchedule> sList;
+ QMap<QString, MyMoneySecurity> secList;
+ QMap<QString, MyMoneyReport> rList;
+ QMap<QString, MyMoneyBudget> bList;
+ QMap<MyMoneySecurityPair, MyMoneyPriceEntries> prList;
+
+ QString m_fromSecurity;
+ QString m_toSecurity;
+
+};
+
+
+class MyMoneyXmlContentHandler : public QXmlContentHandler
+{
+public:
+ MyMoneyXmlContentHandler(MyMoneyStorageXML* reader);
+ virtual ~MyMoneyXmlContentHandler() {}
+ virtual void setDocumentLocator (QXmlLocator * locator) { m_loc = locator; }
+ virtual bool startDocument (void);
+ virtual bool endDocument (void);
+ virtual bool startPrefixMapping(const QString & prefix, const QString & uri);
+ virtual bool endPrefixMapping(const QString & prefix);
+ virtual bool startElement(const QString & namespaceURI, const QString & localName, const QString & qName, const QXmlAttributes & atts);
+ virtual bool endElement(const QString & namespaceURI, const QString & localName, const QString & qName);
+ virtual bool characters(const QString & ch);
+ virtual bool ignorableWhitespace(const QString & ch);
+ virtual bool processingInstruction(const QString & target, const QString & data);
+ virtual bool skippedEntity(const QString & name);
+ virtual QString errorString(void);
+
+private:
+ MyMoneyStorageXML* m_reader;
+ QXmlLocator* m_loc;
+ int m_level;
+ int m_elementCount;
+ QDomDocument m_doc;
+ QDomElement m_baseNode;
+ QDomElement m_currNode;
+ QString m_errMsg;
+};
+
+MyMoneyXmlContentHandler::MyMoneyXmlContentHandler(MyMoneyStorageXML* reader) :
+ m_reader(reader),
+ m_loc(0),
+ m_level(0),
+ m_elementCount(0)
+{
+}
+
+bool MyMoneyXmlContentHandler::startDocument(void)
+{
+ qDebug("startDocument");
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endDocument(void)
+{
+ qDebug("endDocument");
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::skippedEntity (const QString & /* name */)
+{
+ // qDebug(QString("Skipped entity '%1'").arg(name));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::startPrefixMapping (const QString& /*prefix */, const QString & /* uri */)
+{
+ // qDebug(QString("start prefix '%1', '%2'").arg(prefix).arg(uri));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endPrefixMapping (const QString& /* prefix */)
+{
+ // qDebug(QString("end prefix '%1'").arg(prefix));
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::startElement (const QString& /* namespaceURI */, const QString& /* localName */, const QString& qName, const QXmlAttributes & atts)
+{
+ if(m_level == 0) {
+ QString s = qName.lower();
+ if(s == "transaction"
+ || s == "account"
+ || s == "price"
+ || s == "payee"
+ || s == "currency"
+ || s == "security"
+ || s == "keyvaluepairs"
+ || s == "institution"
+ || s == "report"
+ || s == "budget"
+ || s == "fileinfo"
+ || s == "user"
+ || s == "scheduled_tx") {
+ m_baseNode = m_doc.createElement(qName);
+ for(int i=0; i < atts.count(); ++i) {
+ m_baseNode.setAttribute(atts.qName(i), atts.value(i));
+ }
+ m_currNode = m_baseNode;
+ m_level = 1;
+
+ } else if(s == "transactions") {
+ qDebug("reading transactions");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading transactions..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "accounts") {
+ qDebug("reading accounts");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading accounts..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "securities") {
+ qDebug("reading securities");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading securities..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "reports") {
+ qDebug("reading reports");
+ if(atts.count()) {
+ int count = atts.value(QString("count")).toUInt();
+ m_reader->signalProgress(0, count, i18n("Loading reports..."));
+ m_elementCount = 0;
+ }
+ } else if(s == "prices") {
+ qDebug("reading prices");
+ m_elementCount = 0;
+ } else if(s == "pricepair") {
+ if(atts.count()) {
+ m_reader->d->m_fromSecurity = atts.value(QString("from"));
+ m_reader->d->m_toSecurity = atts.value(QString("to"));
+ }
+ }
+
+ } else {
+ m_level++;
+ QDomElement node = m_doc.createElement(qName);
+ for(int i=0; i < atts.count(); ++i) {
+ node.setAttribute(atts.qName(i), atts.value(i));
+ }
+ m_currNode.appendChild(node);
+ m_currNode = node;
+ }
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::endElement(const QString& /* namespaceURI */, const QString& /* localName */, const QString& qName)
+{
+ bool rc = true;
+ QString s = qName.lower();
+ if(m_level) {
+ m_currNode = m_currNode.parentNode().toElement();
+ m_level--;
+ if(!m_level) {
+ try {
+ if(s == "transaction") {
+ MyMoneyTransaction t(m_baseNode);
+ if(!t.id().isEmpty())
+ m_reader->d->tList[t.uniqueSortKey()] = t;
+ } else if(s == "account") {
+ MyMoneyAccount a(m_baseNode);
+ if(!a.id().isEmpty())
+ m_reader->d->aList[a.id()] = a;
+ } else if(s == "payee") {
+ MyMoneyPayee p(m_baseNode);
+ if(!p.id().isEmpty())
+ m_reader->d->pList[p.id()] = p;
+ } else if(s == "currency") {
+ MyMoneySecurity s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->secList[s.id()] = s;
+ } else if(s == "security") {
+ MyMoneySecurity s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->secList[s.id()] = s;
+ } else if(s == "keyvaluepairs") {
+ MyMoneyKeyValueContainer kvp(m_baseNode);
+ m_reader->m_storage->setPairs(kvp.pairs());
+ } else if(s == "institution") {
+ MyMoneyInstitution i(m_baseNode);
+ if(!i.id().isEmpty())
+ m_reader->d->iList[i.id()] = i;
+ } else if(s == "report") {
+ MyMoneyReport r(m_baseNode);
+ if(!r.id().isEmpty())
+ m_reader->d->rList[r.id()] = r;
+ } else if(s == "budget") {
+ MyMoneyBudget b(m_baseNode);
+ if(!b.id().isEmpty())
+ m_reader->d->bList[b.id()] = b;
+ } else if(s == "fileinfo") {
+ rc = m_reader->readFileInformation(m_baseNode);
+ } else if(s == "user") {
+ rc = m_reader->readUserInformation(m_baseNode);
+ } else if(s == "scheduled_tx") {
+ MyMoneySchedule s(m_baseNode);
+ if(!s.id().isEmpty())
+ m_reader->d->sList[s.id()] = s;
+ } else if(s == "price") {
+ MyMoneyPrice p(m_reader->d->m_fromSecurity, m_reader->d->m_toSecurity, m_baseNode);
+ m_reader->d->prList[MyMoneySecurityPair(m_reader->d->m_fromSecurity, m_reader->d->m_toSecurity)][p.date()] = p;
+ } else {
+ m_errMsg = i18n("Unknown XML tag %1 found in line %2").arg(qName).arg(m_loc->lineNumber());
+ kdWarning() << m_errMsg << endl;
+ rc = false;
+ }
+ m_reader->signalProgress(++m_elementCount, 0);
+ } catch(MyMoneyException* e) {
+ m_errMsg = i18n("Exception while creating a %1 element: %2").arg(s).arg(e->what());
+ kdWarning() << m_errMsg << endl;
+ delete e;
+ rc = false;
+ }
+ m_doc = QDomDocument();
+ }
+ } else {
+ if(s == "institutions") {
+ // last institution read, now dump them into the engine
+ m_reader->m_storage->loadInstitutions(m_reader->d->iList);
+ m_reader->d->iList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "accounts") {
+ // last account read, now dump them into the engine
+ m_reader->m_storage->loadAccounts(m_reader->d->aList);
+ m_reader->d->aList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "payees") {
+ // last payee read, now dump them into the engine
+ m_reader->m_storage->loadPayees(m_reader->d->pList);
+ m_reader->d->pList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "transactions") {
+ // last transaction read, now dump them into the engine
+ m_reader->m_storage->loadTransactions(m_reader->d->tList);
+ m_reader->d->tList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "schedules") {
+ // last schedule read, now dump them into the engine
+ m_reader->m_storage->loadSchedules(m_reader->d->sList);
+ m_reader->d->sList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "securities") {
+ // last security read, now dump them into the engine
+ m_reader->m_storage->loadSecurities(m_reader->d->secList);
+ m_reader->d->secList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "currencies") {
+ // last currency read, now dump them into the engine
+ m_reader->m_storage->loadCurrencies(m_reader->d->secList);
+ m_reader->d->secList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "reports") {
+ // last report read, now dump them into the engine
+ m_reader->m_storage->loadReports(m_reader->d->rList);
+ m_reader->d->rList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "budgets") {
+ // last budget read, now dump them into the engine
+ m_reader->m_storage->loadBudgets(m_reader->d->bList);
+ m_reader->d->bList.clear();
+ m_reader->signalProgress(-1, -1);
+ } else if(s == "prices") {
+ // last price read, now dump them into the engine
+ m_reader->m_storage->loadPrices(m_reader->d->prList);
+ m_reader->d->bList.clear();
+ m_reader->signalProgress(-1, -1);
+ }
+ }
+ return rc;
+}
+
+bool MyMoneyXmlContentHandler::characters(const QString& /* ch */)
+{
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::ignorableWhitespace(const QString& /* ch */)
+{
+ return true;
+}
+
+bool MyMoneyXmlContentHandler::processingInstruction(const QString& /* target */, const QString& /* data */)
+{
+ return true;
+}
+
+QString MyMoneyXmlContentHandler::errorString(void)
+{
+ return m_errMsg;
+}
+
+
+
+
+
+
+
+MyMoneyStorageXML::MyMoneyStorageXML() :
+ m_storage(0),
+ m_doc(0),
+ d(new Private())
+{
+}
+
+MyMoneyStorageXML::~MyMoneyStorageXML()
+{
+ delete d;
+}
+
+// Function to read in the file, send to XML parser.
+void MyMoneyStorageXML::readFile(QIODevice* pDevice, IMyMoneySerialize* storage)
+{
+ Q_CHECK_PTR(storage);
+ Q_CHECK_PTR(pDevice);
+ if(!storage)
+ return;
+
+ m_storage = storage;
+
+ m_doc = new QDomDocument;
+ Q_CHECK_PTR(m_doc);
+
+ qDebug("reading file");
+ // creating the QXmlInputSource object based on a QIODevice object
+ // reads all data of the underlying object into memory. I have not
+ // found an object that reads on the fly. I tried to derive one myself,
+ // but there could be a severe problem with decoding when reading
+ // blocks of data and not a stream. So I left it the way it is. (ipwizard)
+ QXmlInputSource xml(pDevice);
+
+ qDebug("start parsing file");
+ MyMoneyXmlContentHandler mmxml(this);
+ QXmlSimpleReader reader;
+ reader.setContentHandler(&mmxml);
+
+ if(!reader.parse(&xml, false)) {
+ delete m_doc;
+ m_doc = NULL;
+ signalProgress(-1, -1);
+ throw new MYMONEYEXCEPTION("File was not parsable!");
+ }
+
+ // check if we need to build up the account balances
+ if(fileVersionRead < 2)
+ m_storage->rebuildAccountBalances();
+
+ delete m_doc;
+ m_doc = NULL;
+
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ m_storage->setLastModificationDate(m_storage->lastModificationDate());
+ m_storage = NULL;
+
+ //hides the progress bar.
+ signalProgress(-1, -1);
+}
+
+void MyMoneyStorageXML::writeFile(QIODevice* qf, IMyMoneySerialize* storage)
+{
+ Q_CHECK_PTR(qf);
+ Q_CHECK_PTR(storage);
+ if(!storage)
+ {
+ return;
+ }
+ m_storage = storage;
+
+ // qDebug("XMLWRITER: Starting file write");
+ m_doc = new QDomDocument("KMYMONEY-FILE");
+ Q_CHECK_PTR(m_doc);
+ QDomProcessingInstruction instruct = m_doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
+ m_doc->appendChild(instruct);
+
+ QDomElement mainElement = m_doc->createElement("KMYMONEY-FILE");
+ m_doc->appendChild(mainElement);
+
+ QDomElement fileInfo = m_doc->createElement("FILEINFO");
+ writeFileInformation(fileInfo);
+ mainElement.appendChild(fileInfo);
+
+ QDomElement userInfo = m_doc->createElement("USER");
+ writeUserInformation(userInfo);
+ mainElement.appendChild(userInfo);
+
+ QDomElement institutions = m_doc->createElement("INSTITUTIONS");
+ writeInstitutions(institutions);
+ mainElement.appendChild(institutions);
+
+ QDomElement payees = m_doc->createElement("PAYEES");
+ writePayees(payees);
+ mainElement.appendChild(payees);
+
+ QDomElement accounts = m_doc->createElement("ACCOUNTS");
+ writeAccounts(accounts);
+ mainElement.appendChild(accounts);
+
+ QDomElement transactions = m_doc->createElement("TRANSACTIONS");
+ writeTransactions(transactions);
+ mainElement.appendChild(transactions);
+
+ QDomElement keyvalpairs = writeKeyValuePairs(m_storage->pairs());
+ mainElement.appendChild(keyvalpairs);
+
+ QDomElement schedules = m_doc->createElement("SCHEDULES");
+ writeSchedules(schedules);
+ mainElement.appendChild(schedules);
+
+ QDomElement equities = m_doc->createElement("SECURITIES");
+ writeSecurities(equities);
+ mainElement.appendChild(equities);
+
+ QDomElement currencies = m_doc->createElement("CURRENCIES");
+ writeCurrencies(currencies);
+ mainElement.appendChild(currencies);
+
+ QDomElement prices = m_doc->createElement("PRICES");
+ writePrices(prices);
+ mainElement.appendChild(prices);
+
+ QDomElement reports = m_doc->createElement("REPORTS");
+ writeReports(reports);
+ mainElement.appendChild(reports);
+
+ QDomElement budgets = m_doc->createElement("BUDGETS");
+ writeBudgets(budgets);
+ mainElement.appendChild(budgets);
+
+ QTextStream stream(qf);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << m_doc->toString();
+
+ delete m_doc;
+ m_doc = NULL;
+
+ //hides the progress bar.
+ signalProgress(-1, -1);
+
+ // this seems to be nonsense, but it clears the dirty flag
+ // as a side-effect.
+ m_storage->setLastModificationDate(m_storage->lastModificationDate());
+
+ m_storage = NULL;
+}
+
+bool MyMoneyStorageXML::readFileInformation(const QDomElement& fileInfo)
+{
+ signalProgress(0, 3, i18n("Loading file information..."));
+ bool rc = true;
+ QDomElement temp = findChildElement("CREATION_DATE", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ QString strDate = QStringEmpty(temp.attribute("date"));
+ m_storage->setCreationDate(stringToDate(strDate));
+ signalProgress(1, 0);
+
+ temp = findChildElement("LAST_MODIFIED_DATE", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ strDate = QStringEmpty(temp.attribute("date"));
+ m_storage->setLastModificationDate(stringToDate(strDate));
+ signalProgress(2, 0);
+
+ temp = findChildElement("VERSION", fileInfo);
+ if (temp == QDomElement()) {
+ rc = false;
+ }
+ QString strVersion = QStringEmpty(temp.attribute("id"));
+ fileVersionRead = strVersion.toUInt(NULL, 16);
+
+ temp = findChildElement("FIXVERSION", fileInfo);
+ if (temp != QDomElement()) {
+ QString strFixVersion = QStringEmpty(temp.attribute("id"));
+ m_storage->setFileFixVersion (strFixVersion.toUInt());
+ }
+ // FIXME The old version stuff used this rather odd number
+ // We now use increments
+ if(fileVersionRead == VERSION_0_60_XML)
+ fileVersionRead = 1;
+ signalProgress(3, 0);
+
+ return rc;
+}
+
+void MyMoneyStorageXML::writeFileInformation(QDomElement& fileInfo)
+{
+ QDomElement creationDate = m_doc->createElement("CREATION_DATE");
+ creationDate.setAttribute("date", dateToString(m_storage->creationDate()));
+ fileInfo.appendChild(creationDate);
+
+ QDomElement lastModifiedDate = m_doc->createElement("LAST_MODIFIED_DATE");
+ lastModifiedDate.setAttribute("date", dateToString(m_storage->lastModificationDate()));
+ fileInfo.appendChild(lastModifiedDate);
+
+ QDomElement version = m_doc->createElement("VERSION");
+
+ version.setAttribute("id", "1");
+ fileInfo.appendChild(version);
+
+ QDomElement fixVersion = m_doc->createElement("FIXVERSION");
+ fixVersion.setAttribute("id", m_storage->fileFixVersion());
+ fileInfo.appendChild(fixVersion);
+}
+
+void MyMoneyStorageXML::writeUserInformation(QDomElement& userInfo)
+{
+ MyMoneyPayee user = m_storage->user();
+ userInfo.setAttribute("name", user.name());
+ userInfo.setAttribute("email", user.email());
+
+ QDomElement address = m_doc->createElement("ADDRESS");
+ address.setAttribute("street", user.address());
+ address.setAttribute("city", user.city());
+ address.setAttribute("county", user.state());
+ address.setAttribute("zipcode", user.postcode());
+ address.setAttribute("telephone", user.telephone());
+
+ userInfo.appendChild(address);
+}
+
+bool MyMoneyStorageXML::readUserInformation(const QDomElement& userElement)
+{
+ bool rc = true;
+ signalProgress(0, 1, i18n("Loading user information..."));
+
+ MyMoneyPayee user;
+ user.setName(QStringEmpty(userElement.attribute("name")));
+ user.setEmail(QStringEmpty(userElement.attribute("email")));
+
+ QDomElement addressNode = findChildElement("ADDRESS", userElement);
+ if(!addressNode.isNull()) {
+ user.setAddress(QStringEmpty(addressNode.attribute("street")));
+ user.setCity(QStringEmpty(addressNode.attribute("city")));
+ user.setState(QStringEmpty(addressNode.attribute("county")));
+ user.setPostcode(QStringEmpty(addressNode.attribute("zipcode")));
+ user.setTelephone(QStringEmpty(addressNode.attribute("telephone")));
+ }
+
+ m_storage->setUser(user);
+ signalProgress(1, 0);
+
+ return rc;
+}
+
+void MyMoneyStorageXML::writeInstitutions(QDomElement& institutions)
+{
+ const QValueList<MyMoneyInstitution> list = m_storage->institutionList();
+ QValueList<MyMoneyInstitution>::ConstIterator it;
+ institutions.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ writeInstitution(institutions, *it);
+}
+
+void MyMoneyStorageXML::writeInstitution(QDomElement& institution, const MyMoneyInstitution& i)
+{
+ i.writeXML(*m_doc, institution);
+}
+
+void MyMoneyStorageXML::writePayees(QDomElement& payees)
+{
+ const QValueList<MyMoneyPayee> list = m_storage->payeeList();
+ QValueList<MyMoneyPayee>::ConstIterator it;
+ payees.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ writePayee(payees, *it);
+}
+
+void MyMoneyStorageXML::writePayee(QDomElement& payee, const MyMoneyPayee& p)
+{
+ p.writeXML(*m_doc, payee);
+}
+
+void MyMoneyStorageXML::writeAccounts(QDomElement& accounts)
+{
+ QValueList<MyMoneyAccount> list;
+ m_storage->accountList(list);
+ QValueList<MyMoneyAccount>::ConstIterator it;
+ accounts.setAttribute("count", list.count()+5);
+
+ writeAccount(accounts, m_storage->asset());
+ writeAccount(accounts, m_storage->liability());
+ writeAccount(accounts, m_storage->expense());
+ writeAccount(accounts, m_storage->income());
+ writeAccount(accounts, m_storage->equity());
+
+ signalProgress(0, list.count(), i18n("Saving accounts..."));
+ int i = 0;
+ for(it = list.begin(); it != list.end(); ++it, ++i) {
+ writeAccount(accounts, *it);
+ signalProgress(i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeAccount(QDomElement& account, const MyMoneyAccount& p)
+{
+ p.writeXML(*m_doc, account);
+}
+
+void MyMoneyStorageXML::writeTransactions(QDomElement& transactions)
+{
+ MyMoneyTransactionFilter filter;
+ filter.setReportAllSplits(false);
+ QValueList<MyMoneyTransaction> list;
+ m_storage->transactionList(list, filter);
+ transactions.setAttribute("count", list.count());
+
+ QValueList<MyMoneyTransaction>::ConstIterator it;
+
+ signalProgress(0, list.count(), i18n("Saving transactions..."));
+
+ int i = 0;
+ for(it = list.begin(); it != list.end(); ++it, ++i)
+ {
+ writeTransaction(transactions, *it);
+ signalProgress(i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeTransaction(QDomElement& transaction, const MyMoneyTransaction& tx)
+{
+ tx.writeXML(*m_doc, transaction);
+}
+
+void MyMoneyStorageXML::writeSchedules(QDomElement& scheduled)
+{
+ const QValueList<MyMoneySchedule> list = m_storage->scheduleList();
+ QValueList<MyMoneySchedule>::ConstIterator it;
+ scheduled.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ this->writeSchedule(scheduled, *it);
+ }
+}
+
+void MyMoneyStorageXML::writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& tx)
+{
+ tx.writeXML(*m_doc, scheduledTx);
+}
+
+void MyMoneyStorageXML::writeSecurities(QDomElement& equities)
+{
+ const QValueList<MyMoneySecurity> securityList = m_storage->securityList();
+ equities.setAttribute("count", securityList.count());
+ if(securityList.size())
+ {
+ for(QValueList<MyMoneySecurity>::ConstIterator it = securityList.begin(); it != securityList.end(); ++it)
+ {
+ writeSecurity(equities, (*it));
+ }
+ }
+}
+
+void MyMoneyStorageXML::writeSecurity(QDomElement& securityElement, const MyMoneySecurity& security)
+{
+ security.writeXML(*m_doc, securityElement);
+}
+
+void MyMoneyStorageXML::writeCurrencies(QDomElement& currencies)
+{
+ const QValueList<MyMoneySecurity> currencyList = m_storage->currencyList();
+ currencies.setAttribute("count", currencyList.count());
+ if(currencyList.size())
+ {
+ for(QValueList<MyMoneySecurity>::ConstIterator it = currencyList.begin(); it != currencyList.end(); ++it)
+ {
+ writeSecurity(currencies, (*it));
+ }
+ }
+}
+
+void MyMoneyStorageXML::writeReports(QDomElement& parent)
+{
+ const QValueList<MyMoneyReport> list = m_storage->reportList();
+ QValueList<MyMoneyReport>::ConstIterator it;
+ parent.setAttribute("count", list.count());
+
+ signalProgress(0, list.count(), i18n("Saving reports..."));
+ unsigned i = 0;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ (*it).writeXML(*m_doc, parent);
+ signalProgress(++i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeBudgets(QDomElement& parent)
+{
+ const QValueList<MyMoneyBudget> list = m_storage->budgetList();
+ QValueList<MyMoneyBudget>::ConstIterator it;
+ parent.setAttribute("count", list.count());
+
+ signalProgress(0, list.count(), i18n("Saving budgets..."));
+ unsigned i = 0;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ writeBudget(parent, (*it));
+ signalProgress(++i, 0);
+ }
+}
+
+void MyMoneyStorageXML::writeBudget(QDomElement& budget, const MyMoneyBudget& b)
+{
+ b.writeXML(*m_doc, budget);
+}
+
+
+QDomElement MyMoneyStorageXML::findChildElement(const QString& name, const QDomElement& root)
+{
+ QDomNode child = root.firstChild();
+ while(!child.isNull())
+ {
+ if(child.isElement())
+ {
+ QDomElement childElement = child.toElement();
+ if(name == childElement.tagName())
+ {
+ return childElement;
+ }
+ }
+
+ child = child.nextSibling();
+ }
+ return QDomElement();
+}
+
+QDomElement MyMoneyStorageXML::writeKeyValuePairs(const QMap<QString, QString> pairs)
+{
+ if(m_doc)
+ {
+ QDomElement keyValPairs = m_doc->createElement("KEYVALUEPAIRS");
+
+ QMap<QString, QString>::const_iterator it;
+ for(it = pairs.begin(); it != pairs.end(); ++it)
+ {
+ QDomElement pair = m_doc->createElement("PAIR");
+ pair.setAttribute("key", it.key());
+ pair.setAttribute("value", it.data());
+ keyValPairs.appendChild(pair);
+ }
+ return keyValPairs;
+ }
+ return QDomElement();
+}
+
+void MyMoneyStorageXML::writePrices(QDomElement& prices)
+{
+ const MyMoneyPriceList list = m_storage->priceList();
+ MyMoneyPriceList::ConstIterator it;
+ prices.setAttribute("count", list.count());
+
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ QDomElement price = m_doc->createElement("PRICEPAIR");
+ price.setAttribute("from", it.key().first);
+ price.setAttribute("to", it.key().second);
+ writePricePair(price, *it);
+ prices.appendChild(price);
+ }
+}
+
+void MyMoneyStorageXML::writePricePair(QDomElement& price, const MyMoneyPriceEntries& p)
+{
+ MyMoneyPriceEntries::ConstIterator it;
+ for(it = p.begin(); it != p.end(); ++it) {
+ QDomElement entry = m_doc->createElement("PRICE");
+ writePrice(entry, *it);
+ price.appendChild(entry);
+ }
+}
+
+void MyMoneyStorageXML::writePrice(QDomElement& price, const MyMoneyPrice& p)
+{
+ price.setAttribute("date", p.date().toString(Qt::ISODate));
+ price.setAttribute("price", p.rate(QString()).toString());
+ price.setAttribute("source", p.source());
+}
+
+void MyMoneyStorageXML::setProgressCallback(void(*callback)(int, int, const QString&))
+{
+ m_progressCallback = callback;
+}
+
+void MyMoneyStorageXML::signalProgress(int current, int total, const QString& msg)
+{
+ if(m_progressCallback != 0)
+ (*m_progressCallback)(current, total, msg);
+}
+
+/*!
+ This convenience function returns all of the remaining data in the
+ device.
+
+ @note It's copied from the original Qt sources and modified to
+ fix a problem with KFilterDev that does not correctly return
+ atEnd() status in certain circumstances which caused our
+ application to lock at startup.
+*/
+QByteArray QIODevice::readAll()
+{
+ if ( isDirectAccess() ) {
+ // we know the size
+ int n = size()-at(); // ### fix for 64-bit or large files?
+ int totalRead = 0;
+ QByteArray ba( n );
+ char* c = ba.data();
+ while ( n ) {
+ int r = readBlock( c, n );
+ if ( r < 0 )
+ return QByteArray();
+ n -= r;
+ c += r;
+ totalRead += r;
+ // If we have a translated file, then it is possible that
+ // we read less bytes than size() reports
+ if ( atEnd() ) {
+ ba.resize( totalRead );
+ break;
+ }
+ }
+ return ba;
+ } else {
+ // read until we reach the end
+ const int blocksize = 512;
+ int nread = 0;
+ QByteArray ba;
+ int r = 1;
+ while ( !atEnd() && r != 0) {
+ ba.resize( nread + blocksize );
+ r = readBlock( ba.data()+nread, blocksize );
+ if ( r < 0 )
+ return QByteArray();
+ nread += r;
+ }
+ ba.resize( nread );
+ return ba;
+ }
+}
+