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.
kmymoney/kmymoney2/converter/mymoneytemplate.cpp

421 lines
14 KiB

/***************************************************************************
mymoneytemplate.cpp - description
-------------------
begin : Sat Aug 14 2004
copyright : (C) 2004 by Thomas Baumgart
email : ipwizard@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 "kdecompat.h"
// ----------------------------------------------------------------------------
// QT Includes
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqapplication.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <klocale.h>
#include <kmessagebox.h>
#include <kio/netaccess.h>
#include <ksavefile.h>
// ----------------------------------------------------------------------------
// Project Includes
#include "mymoneytemplate.h"
MyMoneyTemplate::MyMoneyTemplate() :
m_progressCallback(0)
{
}
MyMoneyTemplate::MyMoneyTemplate(const KURL& url) :
m_progressCallback(0)
{
loadTemplate(url);
}
MyMoneyTemplate::~MyMoneyTemplate()
{
}
bool MyMoneyTemplate::loadTemplate(const KURL& url)
{
TQString filename;
if(!url.isValid()) {
qDebug("Invalid template URL '%s'", url.url().latin1());
return false;
}
m_source = url;
if(url.isLocalFile()) {
filename = url.path();
} else {
bool rc;
rc = KIO::NetAccess::download(url, filename, tqApp->mainWidget());
if(!rc) {
KMessageBox::detailedError(tqApp->mainWidget(),
i18n("Error while loading file '%1'!").arg(url.url()),
KIO::NetAccess::lastErrorString(),
i18n("File access error"));
return false;
}
}
bool rc = true;
TQFile file(filename);
TQFileInfo info(file);
if(!info.isFile()) {
TQString msg=i18n("<b>%1</b> is not a template file.").arg(filename);
KMessageBox::error(tqApp->mainWidget(), TQString("<p>")+msg, i18n("Filetype Error"));
return false;
}
if(file.open(IO_ReadOnly)) {
TQString errMsg;
int errLine, errColumn;
if(!m_doc.setContent(&file, &errMsg, &errLine, &errColumn)) {
TQString msg=i18n("Error while reading template file <b>%1</b> in line %2, column %3").arg(filename).arg(errLine).arg(errColumn);
KMessageBox::detailedError(tqApp->mainWidget(), TQString("<p>")+msg, errMsg, i18n("Template Error"));
rc = false;
} else {
rc = loadDescription();
}
file.close();
} else {
KMessageBox::sorry(tqApp->mainWidget(), i18n("File '%1' not found!").arg(filename));
rc = false;
}
// if a temporary file was constructed by NetAccess::download,
// then it will be removed with the next call. Otherwise, it
// stays untouched on the local filesystem
KIO::NetAccess::removeTempFile(filename);
return rc;
}
bool MyMoneyTemplate::loadDescription(void)
{
int validMask = 0x00;
const int validAccount = 0x01;
const int validTitle = 0x02;
const int validShort = 0x04;
const int validLong = 0x08;
const int invalid = 0x10;
const int validHeader = 0x0F;
TQDomElement rootElement = m_doc.documentElement();
if(!rootElement.isNull()
&& rootElement.tagName() == "kmymoney-account-template") {
TQDomNode child = rootElement.firstChild();
while(!child.isNull() && child.isElement()) {
TQDomElement childElement = child.toElement();
// qDebug("MyMoneyTemplate::import: Processing child node %s", childElement.tagName().data());
if(childElement.tagName() == "accounts") {
m_accounts = childElement.firstChild();
validMask |= validAccount;
} else if(childElement.tagName() == "title") {
m_title = childElement.text();
validMask |= validTitle;
} else if(childElement.tagName() == "shortdesc") {
m_shortDesc = childElement.text();
validMask |= validShort;
} else if(childElement.tagName() == "longdesc") {
m_longDesc = childElement.text();
validMask |= validLong;
} else {
KMessageBox::error(tqApp->mainWidget(), TQString("<p>")+i18n("Invalid tag <b>%1</b> in template file <b>%2</b>!").arg(childElement.tagName()).arg(m_source.prettyURL()));
validMask |= invalid;
}
child = child.nextSibling();
}
}
return validMask == validHeader;
}
bool MyMoneyTemplate::hierarchy(TQMap<TQString, TQListViewItem*>& list, const TQString& parent, TQDomNode account)
{
bool rc = true;
while(rc == true && !account.isNull()) {
if(account.isElement()) {
TQDomElement accountElement = account.toElement();
if(accountElement.tagName() == "account") {
TQString name = TQString("%1:%2").arg(parent).arg(accountElement.attribute("name"));
list[name] = 0;
hierarchy(list, name, account.firstChild());
}
}
account = account.nextSibling();
}
return rc;
}
void MyMoneyTemplate::hierarchy(TQMap<TQString, TQListViewItem*>& list)
{
bool rc = !m_accounts.isNull();
TQDomNode accounts = m_accounts;
while(rc == true && !accounts.isNull() && accounts.isElement()) {
TQDomElement childElement = accounts.toElement();
if(childElement.tagName() == "account"
&& childElement.attribute("name") == "") {
switch(childElement.attribute("type").toUInt()) {
case MyMoneyAccount::Asset:
list[i18n("Asset")] = 0;
rc = hierarchy(list, i18n("Asset"), childElement.firstChild());
break;
case MyMoneyAccount::Liability:
list[i18n("Liability")] = 0;
rc = hierarchy(list, i18n("Liability"), childElement.firstChild());
break;
case MyMoneyAccount::Income:
list[i18n("Income")] = 0;
rc = hierarchy(list, i18n("Income"), childElement.firstChild());
break;
case MyMoneyAccount::Expense:
list[i18n("Expense")] = 0;
rc = hierarchy(list, i18n("Expense"), childElement.firstChild());
break;
case MyMoneyAccount::Equity:
list[i18n("Equity")] = 0;
rc = hierarchy(list, i18n("Equity"), childElement.firstChild());
break;
default:
rc = false;
break;
}
} else {
rc = false;
}
accounts = accounts.nextSibling();
}
}
bool MyMoneyTemplate::importTemplate(void(*callback)(int, int, const TQString&))
{
m_progressCallback = callback;
bool rc = !m_accounts.isNull();
MyMoneyFile* file = MyMoneyFile::instance();
signalProgress(0, m_doc.elementsByTagName("account").count(), i18n("Loading template %1").arg(m_source.url()));
m_accountsRead = 0;
while(rc == true && !m_accounts.isNull() && m_accounts.isElement()) {
TQDomElement childElement = m_accounts.toElement();
if(childElement.tagName() == "account"
&& childElement.attribute("name") == "") {
++m_accountsRead;
MyMoneyAccount parent;
switch(childElement.attribute("type").toUInt()) {
case MyMoneyAccount::Asset:
parent = file->asset();
break;
case MyMoneyAccount::Liability:
parent = file->liability();
break;
case MyMoneyAccount::Income:
parent = file->income();
break;
case MyMoneyAccount::Expense:
parent = file->expense();
break;
case MyMoneyAccount::Equity:
parent = file->equity();
break;
default:
KMessageBox::error(tqApp->mainWidget(), TQString("<p>")+i18n("Invalid top-level account type <b>%1</b> in template file <b>%2</b>!").arg(childElement.attribute("type")).arg(m_source.prettyURL()));
rc = false;
}
if(rc == true) {
rc = createAccounts(parent, childElement.firstChild());
}
} else {
rc = false;
}
m_accounts = m_accounts.nextSibling();
}
signalProgress(-1, -1);
return rc;
}
bool MyMoneyTemplate::createAccounts(MyMoneyAccount& parent, TQDomNode account)
{
bool rc = true;
while(rc == true && !account.isNull()) {
MyMoneyAccount acc;
if(account.isElement()) {
TQDomElement accountElement = account.toElement();
if(accountElement.tagName() == "account") {
signalProgress(++m_accountsRead, 0);
TQValueList<MyMoneyAccount> subAccountList;
TQValueList<MyMoneyAccount>::ConstIterator it;
it = subAccountList.end();
if(!parent.accountList().isEmpty()) {
MyMoneyFile::instance()->accountList(subAccountList, parent.accountList());
for(it = subAccountList.begin(); it != subAccountList.end(); ++it) {
if((*it).name() == accountElement.attribute("name")) {
acc = *it;
break;
}
}
}
if(it == subAccountList.end()) {
// not found, we need to create it
acc.setName(accountElement.attribute("name"));
acc.setAccountType(static_cast<MyMoneyAccount::_accountTypeE>(accountElement.attribute("type").toUInt()));
setFlags(acc, account.firstChild());
try {
MyMoneyFile::instance()->addAccount(acc, parent);
} catch(MyMoneyException *e) {
delete e;
}
}
createAccounts(acc, account.firstChild());
}
}
account = account.nextSibling();
}
return rc;
}
bool MyMoneyTemplate::setFlags(MyMoneyAccount& acc, TQDomNode flags)
{
bool rc = true;
while(rc == true && !flags.isNull()) {
if(flags.isElement()) {
TQDomElement flagElement = flags.toElement();
if(flagElement.tagName() == "flag") {
// make sure, we only store flags we know!
TQString value = flagElement.attribute("name");
if(value == "Tax") {
acc.setValue(value.latin1(), "Yes");
} else {
KMessageBox::error(tqApp->mainWidget(), TQString("<p>")+i18n("Invalid flag type <b>%1</b> for account <b>%3</b> in template file <b>%2</b>!").arg(flagElement.attribute("name")).arg(m_source.prettyURL()).arg(acc.name()));
rc = false;
}
}
}
flags = flags.nextSibling();
}
return rc;
}
void MyMoneyTemplate::signalProgress(int current, int total, const TQString& msg)
{
if(m_progressCallback != 0)
(*m_progressCallback)(current, total, msg);
}
bool MyMoneyTemplate::exportTemplate(void(*callback)(int, int, const TQString&))
{
m_progressCallback = callback;
m_doc = TQDomDocument("KMYMONEY-TEMPLATE");
TQDomProcessingInstruction instruct = m_doc.createProcessingInstruction(TQString("xml"), TQString("version=\"1.0\" encoding=\"utf-8\""));
m_doc.appendChild(instruct);
TQDomElement mainElement = m_doc.createElement("kmymoney-account-template");
m_doc.appendChild(mainElement);
TQDomElement title = m_doc.createElement("title");
mainElement.appendChild(title);
TQDomElement shortDesc = m_doc.createElement("shortdesc");
mainElement.appendChild(shortDesc);
TQDomElement longDesc = m_doc.createElement("longdesc");
mainElement.appendChild(longDesc);
TQDomElement accounts = m_doc.createElement("accounts");
mainElement.appendChild(accounts);
// addAccountStructure(accounts, MyMoneyFile::instance()->asset());
// addAccountStructure(accounts, MyMoneyFile::instance()->liability());
addAccountStructure(accounts, MyMoneyFile::instance()->income());
addAccountStructure(accounts, MyMoneyFile::instance()->expense());
// addAccountStructure(accounts, MyMoneyFile::instance()->equity());
return true;
}
bool MyMoneyTemplate::addAccountStructure(TQDomElement& parent, const MyMoneyAccount& acc)
{
TQDomElement account = m_doc.createElement("account");
parent.appendChild(account);
if(MyMoneyFile::instance()->isStandardAccount(acc.id()))
account.setAttribute(TQString("name"), TQString());
else
account.setAttribute(TQString("name"), acc.name());
account.setAttribute(TQString("type"), acc.accountType());
// FIXME: add tax flag stuff
// any child accounts?
if(acc.accountList().count() > 0) {
TQValueList<MyMoneyAccount> list;
MyMoneyFile::instance()->accountList(list, acc.accountList(), false);
TQValueList<MyMoneyAccount>::Iterator it;
for(it = list.begin(); it != list.end(); ++it) {
addAccountStructure(account, *it);
}
}
return true;
}
bool MyMoneyTemplate::saveTemplate(const KURL& url)
{
TQString filename;
if(!url.isValid()) {
qDebug("Invalid template URL '%s'", url.url().latin1());
return false;
}
if(url.isLocalFile()) {
filename = url.path();
KSaveFile qfile(filename, 0600);
if(qfile.status() == 0) {
saveToLocalFile(qfile.file());
if(!qfile.close()) {
throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
}
} else {
throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").arg(filename));
}
} else {
KTempFile tmpfile;
saveToLocalFile(tmpfile.file());
if(!KIO::NetAccess::upload(tmpfile.name(), url, NULL))
throw new MYMONEYEXCEPTION(i18n("Unable to upload to '%1'").arg(url.url()));
tmpfile.unlink();
}
return true;
}
bool MyMoneyTemplate::saveToLocalFile(TQFile* qfile)
{
TQTextStream stream(qfile);
stream.setEncoding(TQTextStream::UnicodeUTF8);
stream << m_doc.toString();
return true;
}