/***************************************************************************
kmymoneyview.cpp
-------------------
copyright : (C) 2000 by Michael Edwardes
2004 by Thomas Baumgart
email : mte@users.sourceforge.net
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. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
#include "kdecompat.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// ----------------------------------------------------------------------------
// Project Includes
// This is include is required here, because later it will produce
// compile errors on gcc 3.2 as we redefine new() in case of _CHECK_MEMORY
// being defined. To avoid these problems, we just include the header
// already here in this case
#ifdef _CHECK_MEMORY
#include
#endif
#include "../dialogs/kendingbalancedlg.h"
#include "../dialogs/kchooseimportexportdlg.h"
#include "../dialogs/kcsvprogressdlg.h"
#include "../dialogs/kimportdlg.h"
#include "../dialogs/kexportdlg.h"
#include "../dialogs/knewloanwizard.h"
#include "../dialogs/kcurrencyeditdlg.h"
#include "../dialogs/kfindtransactiondlg.h"
#include "../dialogs/knewbankdlg.h"
#include "../dialogs/knewfiledlg.h"
#include "../mymoney/storage/mymoneyseqaccessmgr.h"
#include "../mymoney/storage/mymoneydatabasemgr.h"
#include "../mymoney/storage/imymoneystorageformat.h"
#include "../mymoney/storage/mymoneystoragebin.h"
#include "../mymoney/mymoneyexception.h"
#include "../mymoney/storage/mymoneystoragexml.h"
#include "../mymoney/storage/mymoneystoragesql.h"
#include "../converter/mymoneygncreader.h"
#include "../mymoney/storage/mymoneystorageanon.h"
#include
#include
#include "kmymoneyview.h"
#include "khomeview.h"
#include "kaccountsview.h"
#include "kcategoriesview.h"
#include "kinstitutionsview.h"
#include "kpayeesview.h"
#include "kscheduledview.h"
#include "kgloballedgerview.h"
#include "kinvestmentview.h"
#include "kreportsview.h"
#include "kbudgetview.h"
#include "kforecastview.h"
#include
#include "../kmymoney2.h"
#include "../kmymoneyutils.h"
#include
#define COMPRESSION_MIME_TYPE "application/x-gzip"
#define RECOVER_KEY_ID "0xD2B08440"
KMyMoneyView::KMyMoneyView(TQWidget *tqparent, const char *name)
: KJanusWidget(tqparent, name, KJanusWidget::IconList),
// m_bankRightClick(false),
m_inConstructor(true),
m_fileOpen(false),
m_fmode(0600)
{
// the global variable kmymoney2 is not yet assigned. So we construct it here
TQObject* kmymoney2 = tqparent->tqparent();
const int iconSize = (KMyMoneyGlobalSettings::iconSize()+1)*16;
newStorage();
// Page 0
m_homeViewFrame = addVBoxPage( i18n("Home"), i18n("Home"),
DesktopIcon("home", iconSize));
m_homeView = new KHomeView(m_homeViewFrame, "HomeView");
connect(m_homeView, TQT_SIGNAL(ledgerSelected(const TQString&, const TQString&)),
this, TQT_SLOT(slotLedgerSelected(const TQString&, const TQString&)));
connect(m_homeView, TQT_SIGNAL(scheduleSelected(const TQString&)),
this, TQT_SLOT(slotScheduleSelected(const TQString&)));
connect(m_homeView, TQT_SIGNAL(reportSelected(const TQString&)),
this, TQT_SLOT(slotShowReport(const TQString&)));
// Page 1
m_institutionsViewFrame = addVBoxPage( i18n("Institutions"), i18n("Institutions"),
DesktopIcon("institutions", iconSize));
addTitleBar(m_institutionsViewFrame, i18n("Institutions"));
m_institutionsView = new KInstitutionsView(m_institutionsViewFrame, "InstitutionsView");
connect(m_institutionsView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectInstitution(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowInstitutionContextMenu(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotInstitutionEdit(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotAccountOpen(const MyMoneyObject&)));
connect(m_institutionsView, TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyInstitution&)), kmymoney2, TQT_SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyInstitution&)));
connect(this, TQT_SIGNAL(reconciliationStarts(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)), m_institutionsView, TQT_SLOT(slotReconcileAccount(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)));
// Page 2
m_accountsViewFrame = addVBoxPage( i18n("Accounts"), i18n("Accounts"),
DesktopIcon("accounts", iconSize));
addTitleBar(m_accountsViewFrame, i18n("Accounts"));
m_accountsView = new KAccountsView(m_accountsViewFrame, "AccountsView");
connect(m_accountsView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_accountsView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectInstitution(const MyMoneyObject&)));
connect(m_accountsView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectInvestment(const MyMoneyObject&)));
connect(m_accountsView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
connect(m_accountsView, TQT_SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotAccountOpen(const MyMoneyObject&)));
connect(m_accountsView, TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, TQT_SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyAccount&)));
connect(this, TQT_SIGNAL(kmmFilePlugin(unsigned int)), m_accountsView, TQT_SLOT(slotUpdateIconPos(unsigned int)));
connect(this, TQT_SIGNAL(reconciliationStarts(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)), m_accountsView, TQT_SLOT(slotReconcileAccount(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)));
// Page 3
m_scheduleViewFrame = addVBoxPage( i18n("Scheduled\ntransactions"), i18n("Bills & Reminders"),
DesktopIcon("schedule", iconSize));
addTitleBar(m_scheduleViewFrame, i18n("Scheduled transactions"));
m_scheduledView = new KScheduledView(m_scheduleViewFrame, "ScheduledView");
connect(kmymoney2, TQT_SIGNAL(fileLoaded(const KURL&)), m_scheduledView, TQT_SLOT(slotReloadView()));
connect(m_scheduledView, TQT_SIGNAL(scheduleSelected(const MyMoneySchedule&)), kmymoney2, TQT_SLOT(slotSelectSchedule(const MyMoneySchedule&)));
connect(m_scheduledView, TQT_SIGNAL(openContextMenu()), kmymoney2, TQT_SLOT(slotShowScheduleContextMenu()));
connect(m_scheduledView, TQT_SIGNAL(enterSchedule()), kmymoney2, TQT_SLOT(slotScheduleEnter()));
connect(m_scheduledView, TQT_SIGNAL(skipSchedule()), kmymoney2, TQT_SLOT(slotScheduleSkip()));
connect(m_scheduledView, TQT_SIGNAL(editSchedule()), kmymoney2, TQT_SLOT(slotScheduleEdit()));
// Page 4
m_categoriesViewFrame = addVBoxPage( i18n("Categories"), i18n("Categories"),
DesktopIcon("categories", iconSize));
addTitleBar(m_categoriesViewFrame, i18n("Categories"));
m_categoriesView = new KCategoriesView(m_categoriesViewFrame, "CategoriesView");
connect(m_categoriesView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_categoriesView, TQT_SIGNAL(selectObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectInstitution(const MyMoneyObject&)));
connect(m_categoriesView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowAccountContextMenu(const MyMoneyObject&)));
connect(m_categoriesView, TQT_SIGNAL(openObject(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotAccountOpen(const MyMoneyObject&)));
connect(m_categoriesView, TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), kmymoney2, TQT_SLOT(slotReparentAccount(const MyMoneyAccount&, const MyMoneyAccount&)));
// Page 5
m_payeesViewFrame = addVBoxPage( i18n("Payees"), i18n("Payees"),
DesktopIcon("payee", iconSize));
addTitleBar(m_payeesViewFrame, i18n("Payees"));
m_payeesView = new KPayeesView(m_payeesViewFrame, "PayeesView");
connect(kmymoney2, TQT_SIGNAL(payeeCreated(const TQString&)), m_payeesView, TQT_SLOT(slotSelectPayeeAndTransaction(const TQString&)));
connect(kmymoney2, TQT_SIGNAL(payeeRename()), m_payeesView, TQT_SLOT(slotStartRename()));
connect(m_payeesView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowPayeeContextMenu()));
connect(m_payeesView, TQT_SIGNAL(selectObjects(const TQValueList&)), kmymoney2, TQT_SLOT(slotSelectPayees(const TQValueList&)));
connect(m_payeesView, TQT_SIGNAL(transactionSelected(const TQString&, const TQString&)),
this, TQT_SLOT(slotLedgerSelected(const TQString&, const TQString&)));
// Page 6
m_ledgerViewFrame = addVBoxPage( i18n("Ledgers"), i18n("Ledgers"),
DesktopIcon("ledger", iconSize));
m_ledgerView = new KGlobalLedgerView(m_ledgerViewFrame, "GlobalLedgerView");
connect(m_ledgerView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_ledgerView, TQT_SIGNAL(openContextMenu()), kmymoney2, TQT_SLOT(slotShowTransactionContextMenu()));
connect(m_ledgerView, TQT_SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)), kmymoney2, TQT_SLOT(slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions&)));
connect(m_ledgerView, TQT_SIGNAL(newTransaction()), kmymoney2, TQT_SLOT(slotTransactionsNew()));
connect(m_ledgerView, TQT_SIGNAL(cancelOrEndEdit(bool&)), kmymoney2, TQT_SLOT(slotTransactionsCancelOrEnter(bool&)));
connect(m_ledgerView, TQT_SIGNAL(startEdit()), kmymoney2, TQT_SLOT(slotTransactionsEdit()));
connect(m_ledgerView, TQT_SIGNAL(endEdit()), kmymoney2, TQT_SLOT(slotTransactionsEnter()));
connect(m_ledgerView, TQT_SIGNAL(toggleReconciliationFlag()), kmymoney2, TQT_SLOT(slotToggleReconciliationFlag()));
connect(this, TQT_SIGNAL(reconciliationStarts(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)), m_ledgerView, TQT_SLOT(slotSetReconcileAccount(const MyMoneyAccount&, const TQDate&, const MyMoneyMoney&)));
connect(kmymoney2, TQT_SIGNAL(selectAllTransactions()), m_ledgerView, TQT_SLOT(slotSelectAllTransactions()));
// Page 7
m_investmentViewFrame = addVBoxPage( i18n("Investments"), i18n("Investments"),
DesktopIcon("investments", iconSize));
addTitleBar(m_investmentViewFrame, i18n("Investments"));
m_investmentView = new KInvestmentView(m_investmentViewFrame, "InvestmentView");
connect(m_investmentView, TQT_SIGNAL(accountSelected(const TQString&, const TQString&)),
this, TQT_SLOT(slotLedgerSelected(const TQString&, const TQString&)));
connect(m_investmentView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_investmentView, TQT_SIGNAL(investmentRightMouseClick()), kmymoney2, TQT_SLOT(slotShowInvestmentContextMenu()));
// Page 8
m_reportsViewFrame = addVBoxPage(i18n("Reports"), i18n("Reports"),
DesktopIcon("report", iconSize));
m_reportsView = new KReportsView(m_reportsViewFrame, "ReportsView");
// Page 9
m_budgetViewFrame = addVBoxPage(i18n("Budgets"), i18n("Budgets"),
DesktopIcon("budget", iconSize));
addTitleBar(m_budgetViewFrame, i18n("Budgets"));
m_budgetView = new KBudgetView(m_budgetViewFrame, "BudgetView");
connect(kmymoney2, TQT_SIGNAL(fileLoaded(const KURL&)), m_budgetView, TQT_SLOT(slotRefreshView()));
connect(m_budgetView, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), kmymoney2, TQT_SLOT(slotShowBudgetContextMenu()));
connect(m_budgetView, TQT_SIGNAL(selectObjects(const TQValueList&)), kmymoney2, TQT_SLOT(slotSelectBudget(const TQValueList&)));
connect(kmymoney2, TQT_SIGNAL(budgetRename()), m_budgetView, TQT_SLOT(slotStartRename()));
// Page 10
m_forecastViewFrame = addVBoxPage( i18n("Forecast"), i18n("Forecast"),
DesktopIcon("forcast", iconSize));
addTitleBar(m_forecastViewFrame, i18n("Forecast"));
m_forecastView = new KForecastView(m_forecastViewFrame, "ForecastView");
// get rid of the title text
TQWidget* widget = dynamic_cast(child("KJanusWidgetTitleLabel", TQLABEL_OBJECT_NAME_STRING));
if(widget)
widget->hide();
// and the separator below it
widget = dynamic_cast(child(0, "KSeparator"));
if(widget)
widget->hide();
// select the page first, before connecting the aboutToShow signal
// because we don't want to override the information stored in the config file
showPage(0);
connect(this, TQT_SIGNAL(aboutToShowPage(TQWidget*)), this, TQT_SLOT(slotRememberPage(TQWidget*)));
m_inConstructor = false;
}
KMyMoneyView::~KMyMoneyView()
{
removeStorage();
}
void KMyMoneyView::addTitleBar(TQWidget* tqparent, const TQString& title)
{
KMyMoneyTitleLabel* label = new KMyMoneyTitleLabel( tqparent, "titleLabel" );
label->setMinimumSize( TQSize( 100, 30 ) );
label->setRightImageFile("pics/titlelabel_background.png" );
label->setText(title);
}
void KMyMoneyView::showTitleBar(bool show)
{
TQObjectList *l = queryList( 0, "titleLabel" );
TQObjectListIterator it( *l ); // iterate over the labels
TQObject *obj;
while ( (obj = it.current()) != 0 ) {
// for each found object...
++it;
((TQWidget*)obj)->setShown( show );
}
delete l; // delete the list, not the objects
}
bool KMyMoneyView::showPage(int index)
{
// reset all selected items before showing the selected view
// but not while we're in our own constructor
if(!m_inConstructor && index != activePageIndex()) {
kmymoney2->slotResetSelections();
}
// pretend we're in the constructor to avoid calling the
// above resets. For some reason which I don't know the details
// of, KJanusWidget::showPage() calls itself recursively. This
// screws up the action handling, as items could have been selected
// in the meantime. We prevent this by setting the m_inConstructor
// to true and reset it to the previos value when we leave this method.
bool prevConstructor = m_inConstructor;
m_inConstructor = true;
bool rc = KJanusWidget::showPage(index);
m_inConstructor = prevConstructor;
if(!m_inConstructor) {
// fixup some actions that are dependant on the view
// this does not work during construction
kmymoney2->slotUpdateActions();
}
return rc;
}
bool KMyMoneyView::canPrint(void)
{
bool rc = (
activePageIndex() == pageIndex(m_reportsViewFrame) ||
activePageIndex() == pageIndex(m_homeViewFrame)
);
return rc;
}
bool KMyMoneyView::canCreateTransactions(const KMyMoneyRegister::SelectedTransactions& /* list */, TQString& tooltip) const
{
// we can only create transactions in the ledger view so
// we check that this is the active page
bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
if(rc)
rc = m_ledgerView->canCreateTransactions(tooltip);
else
tooltip = i18n("Creating transactions can only be performed in the ledger view");
return rc;
}
bool KMyMoneyView::canModifyTransactions(const KMyMoneyRegister::SelectedTransactions& list, TQString& tooltip) const
{
// we can only modify transactions in the ledger view so
// we check that this is the active page
bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
if(rc) {
rc = m_ledgerView->canModifyTransactions(list, tooltip);
} else {
tooltip = i18n("Modifying transactions can only be performed in the ledger view");
}
return rc;
}
bool KMyMoneyView::canDuplicateTransactions(const KMyMoneyRegister::SelectedTransactions& list, TQString& tooltip) const
{
// we can only duplicate transactions in the ledger view so
// we check that this is the active page
bool rc = (activePageIndex() == pageIndex(m_ledgerViewFrame));
if(rc) {
rc = m_ledgerView->canDuplicateTransactions(list, tooltip);
} else {
tooltip = i18n("Duplicating transactions can only be performed in the ledger view");
}
return rc;
}
bool KMyMoneyView::canEditTransactions(const KMyMoneyRegister::SelectedTransactions& list, TQString& tooltip) const
{
bool rc;
// we can only edit transactions in the ledger view so
// we check that this is the active page
if((rc = canModifyTransactions(list, tooltip)) == true) {
tooltip = i18n("Edit the current selected transactions");
rc = m_ledgerView->canEditTransactions(list, tooltip);
}
return rc;
}
bool KMyMoneyView::createNewTransaction(void)
{
bool rc = false;
KMyMoneyRegister::SelectedTransactions list;
TQString txt;
if(canCreateTransactions(list, txt)) {
rc = m_ledgerView->selectEmptyTransaction();
}
return rc;
}
TransactionEditor* KMyMoneyView::startEdit(const KMyMoneyRegister::SelectedTransactions& list)
{
TransactionEditor* editor = 0;
TQString txt;
if(canEditTransactions(list, txt) || canCreateTransactions(list, txt)) {
editor = m_ledgerView->startEdit(list);
}
return editor;
}
void KMyMoneyView::newStorage(storageTypeE t)
{
removeStorage();
MyMoneyFile* file = MyMoneyFile::instance();
if (t == Memory) file->attachStorage(new MyMoneySeqAccessMgr);
else file->attachStorage(new MyMoneyDatabaseMgr);
}
void KMyMoneyView::removeStorage(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
IMyMoneyStorage* p = file->storage();
if(p != 0) {
file->detachStorage(p);
delete p;
}
}
void KMyMoneyView::enableViews(int state)
{
if(state == -1)
state = m_fileOpen;
m_accountsViewFrame->setEnabled(state);
m_institutionsViewFrame->setEnabled(state);
m_scheduleViewFrame->setEnabled(state);
m_categoriesViewFrame->setEnabled(state);
m_payeesViewFrame->setEnabled(state);
m_budgetViewFrame->setEnabled(state);
m_ledgerViewFrame->setEnabled(state);
m_investmentViewFrame->setEnabled(state);
m_reportsViewFrame->setEnabled(state);
m_forecastViewFrame->setEnabled(state);
emit viewStateChanged(state != 0);
}
void KMyMoneyView::slotLedgerSelected(const TQString& _accId, const TQString& transaction)
{
MyMoneyAccount acc = MyMoneyFile::instance()->account(_accId);
TQString accId(_accId);
switch(acc.accountType()) {
case MyMoneyAccount::Stock:
// if a stock account is selected, we show the
// the corresponding tqparent (investment) account
acc = MyMoneyFile::instance()->account(acc.parentAccountId());
accId = acc.id();
// tricky fall through here
case MyMoneyAccount::Checkings:
case MyMoneyAccount::Savings:
case MyMoneyAccount::Cash:
case MyMoneyAccount::CreditCard:
case MyMoneyAccount::Loan:
case MyMoneyAccount::Asset:
case MyMoneyAccount::Liability:
case MyMoneyAccount::AssetLoan:
case MyMoneyAccount::Income:
case MyMoneyAccount::Expense:
case MyMoneyAccount::Investment:
case MyMoneyAccount::Equity:
showPage(pageIndex(m_ledgerViewFrame));
m_ledgerView->slotSelectAccount(accId, transaction);
break;
case MyMoneyAccount::CertificateDep:
case MyMoneyAccount::MoneyMarket:
case MyMoneyAccount::Currency:
qDebug("No ledger view available for account type %d", acc.accountType());
break;
default:
qDebug("Unknown account type %d in KMyMoneyView::slotLedgerSelected", acc.accountType());
break;
}
}
void KMyMoneyView::slotPayeeSelected(const TQString& payee, const TQString& account, const TQString& transaction)
{
showPage(pageIndex(m_payeesViewFrame));
m_payeesView->slotSelectPayeeAndTransaction(payee, account, transaction);
}
void KMyMoneyView::slotScheduleSelected(const TQString& scheduleId)
{
MyMoneySchedule sched = MyMoneyFile::instance()->schedule(scheduleId);
kmymoney2->slotSelectSchedule(sched);
}
void KMyMoneyView::slotShowReport(const TQString& reportid)
{
showPage(pageIndex(m_reportsViewFrame));
m_reportsView->slotOpenReport(reportid);
}
void KMyMoneyView::slotShowReport(const MyMoneyReport& report)
{
showPage(pageIndex(m_reportsViewFrame));
m_reportsView->slotOpenReport(report);
}
bool KMyMoneyView::fileOpen(void)
{
return m_fileOpen;
}
void KMyMoneyView::closeFile(void)
{
if ( m_reportsView )
m_reportsView->slotCloseAll();
emit kmmFilePlugin (preClose);
if (isDatabase())
MyMoneyFile::instance()->storage()->close(); // to log off a database user
newStorage();
slotShowHomePage();
emit kmmFilePlugin (postClose);
m_fileOpen = false;
}
void KMyMoneyView::ungetString(TQIODevice *qfile, char *buf, int len)
{
buf = &buf[len-1];
while(len--) {
qfile->ungetch(*buf--);
}
}
bool KMyMoneyView::readFile(const KURL& url)
{
TQString filename;
// newStorage();
m_fileOpen = false;
bool isEncrypted = false;
IMyMoneyStorageFormat* pReader = NULL;
#if KDE_IS_VERSION(3,2,0)
if(!url.isValid()) {
#else
if(url.isMalformed()) {
#endif
qDebug("Invalid URL '%s'", url.url().latin1());
return false;
}
if (url.protocol() == "sql") { // handle reading of database
//newStorage(Database);
MyMoneyFile::instance()->detachStorage();
m_fileType = KmmDb;
// get rid of the mode parameter which is now redundant
KURL newUrl(url);
if (!url.queryItem("mode").isNull()) {
newUrl.removeQueryItem("mode");
}
return (openDatabase(newUrl)); // on error, any message will have been displayed
}
newStorage();
if(url.isLocalFile()) {
filename = url.path();
} else {
if(!KIO::NetAccess::download(url, filename, NULL)) {
KMessageBox::detailedError(this,
i18n("Error while loading file '%1'!").tqarg(url.url()),
KIO::NetAccess::lastErrorString(),
i18n("File access error"));
return false;
}
}
// let's glimps into the file to figure out, if it's one
// of the old (uncompressed) or new (compressed) files.
TQFile file(filename);
TQFileInfo info(file);
if(!info.isFile()) {
TQString msg=i18n("%1 is not a KMyMoney file.").tqarg(filename);
KMessageBox::error(this, TQString("")+msg, i18n("Filetype Error"));
return false;
}
m_fmode = 0600;
m_fmode |= info.permission(TQFileInfo::ReadGroup) ? 040 : 0;
m_fmode |= info.permission(TQFileInfo::WriteGroup) ? 020 : 0;
m_fmode |= info.permission(TQFileInfo::ReadOther) ? 004 : 0;
m_fmode |= info.permission(TQFileInfo::WriteOther) ? 002 : 0;
TQIODevice *qfile = 0;
bool rc = true;
// There's a problem with the KFilterDev and KGPGFile classes:
// One supports the at(n) member but not ungetch() together with
// readBlock() and the other does not provide an at(n) method but
// supports readBlock() that considers the ungetch() buffer. TQFile
// supports everything so this is not a problem. We solve the problem
// for now by keeping track of which method can be used.
bool haveAt = true;
emit kmmFilePlugin (preOpen);
::timetrace("start reading file");
if(file.open(IO_ReadOnly)) {
TQByteArray hdr(2);
int cnt;
cnt = file.readBlock(hdr.data(), 2);
file.close();
if(cnt == 2) {
if(TQString(hdr) == TQString("\037\213")) { // gzipped?
::timetrace("detected GZIP");
qfile = KFilterDev::deviceForFile(filename, COMPRESSION_MIME_TYPE);
} else if(TQString(hdr) == TQString("--")){ // PGP ASCII armored?
::timetrace("detected GPG");
if(KGPGFile::GPGAvailable()) {
::timetrace("have GPG");
qfile = TQT_TQIODEVICE(new KGPGFile(filename));
haveAt = false;
isEncrypted = true;
} else {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("GPG is not available for decryption of file %1").tqarg(filename)));
qfile = TQT_TQIODEVICE(new TQFile(file.name()));
}
} else {
// we can't use file directly, as we delete qfile later on
qfile = TQT_TQIODEVICE(new TQFile(file.name()));
}
::timetrace("open file");
if(qfile->open(IO_ReadOnly)) {
try {
hdr.resize(8);
if(qfile->readBlock(hdr.data(), 8) == 8) {
if(haveAt)
qfile->at(0);
else
ungetString(qfile, hdr.data(), 8);
// Ok, we got the first block of 8 bytes. Read in the two
// unsigned long int's by preserving endianess. This is
// achieved by reading them through a TQDataStream object
TQ_INT32 magic0, magic1;
TQDataStream s(hdr, IO_ReadOnly);
s >> magic0;
s >> magic1;
// If both magic numbers match (we actually read in the
// text 'KMyMoney' then we assume a binary file and
// construct a reader for it. Otherwise, we construct
// an XML reader object.
//
// The expression magic0 < 30 is only used to create
// a binary reader if we assume an old binary file. This
// should be removed at some point. An alternative is to
// check the beginning of the file against an pattern
// of the XML file (e.g. '?readBlock(hdr.data(), 70) == 70) {
if(haveAt)
qfile->at(0);
else
ungetString(qfile, hdr.data(), 70);
TQRegExp kmyexp("");
TQRegExp gncexp("setProgressCallback(&KMyMoneyView::progressCallback);
::timetrace("read data to memory");
pReader->readFile(qfile, dynamic_cast (MyMoneyFile::instance()->storage()));
::timetrace("done reading to memory");
} else {
if(m_fileType == KmmBinary) {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("File %1 contains the old binary format used by KMyMoney. Please use an older version of KMyMoney (0.8.x) that still supports this format to convert it to the new XML based format.").tqarg(filename)));
} else {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("File %1 contains an unknown file format!").tqarg(filename)));
}
rc = false;
}
} else {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("Cannot read from file %1!").tqarg(filename)));
rc = false;
}
} catch (MyMoneyException *e) {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("Cannot load file %1. Reason: %2").tqarg(filename, e->what())));
delete e;
rc = false;
}
if(pReader) {
pReader->setProgressCallback(0);
delete pReader;
}
qfile->close();
} else {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("File %1 not found!").tqarg(filename)));
rc = false;
}
delete qfile;
}
} else {
KMessageBox::sorry(this, TQString("%1"). arg(i18n("File %1 not found!").tqarg(filename)));
rc = false;
}
::timetrace("done reading file");
if(rc == false)
return rc;
// make sure we setup the encryption key correctly
MyMoneyFileTransaction ft;
if(isEncrypted && MyMoneyFile::instance()->value("kmm-encryption-key").isEmpty()) {
MyMoneyFile::instance()->setValue("kmm-encryption-key", KMyMoneyGlobalSettings::gpgRecipientList().join(","));
}
// make sure we setup the name of the base accounts in translated form
try {
MyMoneyFile* file = MyMoneyFile::instance();
checkAccountName(file->asset(), i18n("Asset"));
checkAccountName(file->liability(), i18n("Liability"));
checkAccountName(file->income(), i18n("Income"));
checkAccountName(file->expense(), i18n("Expense"));
checkAccountName(file->equity(), i18n("Equity"));
ft.commit();
} catch(MyMoneyException* e) {
delete e;
}
// 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 initializeStorage();
}
void KMyMoneyView::checkAccountName(const MyMoneyAccount& _acc, const TQString& name) const
{
MyMoneyFile* file = MyMoneyFile::instance();
if(_acc.name() != name) {
MyMoneyAccount acc(_acc);
acc.setName(name);
file->modifyAccount(acc);
}
}
bool KMyMoneyView::openDatabase (const KURL& url) {
::timetrace("start opening database");
m_fileOpen = false;
// open the database
IMyMoneySerialize* pStorage = dynamic_cast (MyMoneyFile::instance()->storage());
MyMoneyDatabaseMgr* pDBMgr = 0;
if (! pStorage) {
pDBMgr = new MyMoneyDatabaseMgr;
pStorage = dynamic_cast (pDBMgr);
}
KSharedPtr reader = pStorage->connectToDatabase (url);
KURL dbURL (url);
bool retry = true;
while (retry) {
switch (reader->open(dbURL, IO_ReadWrite)) {
case 0: // opened okay
retry = false;
break;
case 1: // permanent error
KMessageBox::detailedError (this, i18n("Can't open database %1\n").tqarg(dbURL.prettyURL()), reader->lastError());
if (pDBMgr) {
removeStorage();
delete pDBMgr;
}
return false;
case -1: // retryable error
if (KMessageBox::warningYesNo (this, reader->lastError(), PACKAGE) == KMessageBox::No) {
if (pDBMgr) {
removeStorage();
delete pDBMgr;
}
return false;
} else {
TQString options = dbURL.queryItem("options") + ",override";
dbURL.removeQueryItem("mode"); // now redundant
dbURL.removeQueryItem("options");
dbURL.addQueryItem("options", options);
}
}
}
if (pDBMgr) {
removeStorage();
MyMoneyFile::instance()->attachStorage(pDBMgr);
}
// single user mode; read some of the data into memory
// FIXME - readFile no longer relevant?
// tried removing it but then then got no indication that loading was complete
// also, didn't show home page
reader->setProgressCallback(&KMyMoneyView::progressCallback);
if (!reader->readFile()) {
KMessageBox::detailedError (0,
i18n("An unrecoverable error occurred while reading the database"),
reader->lastError().latin1(),
i18n("Database malfunction"));
return false;
}
m_fileOpen = true;
reader->setProgressCallback(0);
::timetrace("done opening database");
return initializeStorage();
}
bool KMyMoneyView::initializeStorage()
{
bool blocked = MyMoneyFile::instance()->signalsBlocked();
MyMoneyFile::instance()->blockSignals(true);
// we check, if we have any currency in the file. If not, we load
// all the default currencies we know.
MyMoneyFileTransaction ft;
try {
loadDefaultCurrencies();
loadAncientCurrencies();
ft.commit();
} catch(MyMoneyException *e) {
delete e;
MyMoneyFile::instance()->blockSignals(blocked);
return false;
}
// make sure, we have a base currency and all accounts are
// also assigned to a currency.
if(MyMoneyFile::instance()->baseCurrency().id().isEmpty()) {
// Stay in this endless loop until we have a base currency,
// as without it the application does not work anymore.
while(MyMoneyFile::instance()->baseCurrency().id().isEmpty())
selectBaseCurrency();
} else {
// in some odd intermediate cases there could be files out there
// that have a base currency set, but still have accounts that
// do not have a base currency assigned. This call will take
// care of it. We can safely remove it later.
//
// Another work-around for this scenario is to remove the base
// currency setting from the XML file by removing the line
//
//
//
// and restart the application with this file. This will force to
// run the above loop.
selectBaseCurrency();
}
KConfig *config = KGlobal::config();
int page;
config->setGroup("General Options");
if(KMyMoneyGlobalSettings::startLastViewSelected() != 0) {
config->setGroup("Last Use Settings");
page = config->readNumEntry("LastViewSelected", 0);
} else {
page = pageIndex(m_homeViewFrame);
}
::timetrace("start fixing file");
// For debugging purposes, we can turn off the automatic fix manually
// by setting the entry in kmymoney2rc to true
config->setGroup("General Options");
if(config->readBoolEntry("SkipFix", false) != true) {
MyMoneyFileTransaction ft;
try {
// Check if we have to modify the file before we allow to work with it
IMyMoneyStorage* s = MyMoneyFile::instance()->storage();
while (s->fileFixVersion() < s->currentFixVersion()) {
qDebug("%s", (TQString("testing fileFixVersion %1 < %2").tqarg(s->fileFixVersion()).tqarg(s->currentFixVersion())).data());
switch (s->fileFixVersion()) {
case 0:
fixFile_0();
s->setFileFixVersion(1);
break;
case 1:
fixFile_1();
s->setFileFixVersion(2);
break;
case 2:
fixFile_2();
s->setFileFixVersion(3);
break;
// add new levels above. Don't forget to increase currentFixVersion() for all
// the storage backends this fix applies to
default:
throw new MYMONEYEXCEPTION(i18n("Unknown fix level in input file"));
}
}
ft.commit();
} catch(MyMoneyException *e) {
delete e;
MyMoneyFile::instance()->blockSignals(blocked);
return false;
}
} else {
qDebug("Skipping automatic transaction fix!");
}
MyMoneyFile::instance()->blockSignals(blocked);
// FIXME: we need to check, if it's necessary to have this
// automatic funcitonality
// if there's no asset account, then automatically start the
// new account wizard
// kmymoney2->createInitialAccount();
::timetrace("file open");
m_fileOpen = true;
emit kmmFilePlugin (postOpen);
// inform everyone about new data
MyMoneyFile::instance()->preloadCache();
MyMoneyFile::instance()->forceDataChanged();
// if we currently see a different page, then select the right one
if(page != activePageIndex()) {
showPage(page);
}
return true;
}
void KMyMoneyView::saveToLocalFile(TQFile* qfile, IMyMoneyStorageFormat* pWriter, bool plaintext, const TQString& keyList)
{
TQIODevice *dev = TQT_TQIODEVICE(qfile);
KFilterBase *base = 0;
TQIODevice *statusDevice = dev;
bool encryptedOk = true;
bool encryptRecover = false;
if(!keyList.isEmpty()) {
if(!KGPGFile::GPGAvailable()) {
KMessageBox::sorry(this, i18n("GPG does not seem to be installed on your system. Please make sure, that GPG can be found using the standard search path. This time, encryption is disabled."), i18n("GPG not found"));
encryptedOk = false;
}
if(KMyMoneyGlobalSettings::encryptRecover()) {
encryptRecover = true;
if(!KGPGFile::keyAvailable(TQString(RECOVER_KEY_ID))) {
KMessageBox::sorry(this, TQString("")+i18n("You have selected to encrypt your data also with the KMyMoney recover key, but the key with id
%1
has not been found in your keyring at this time. Please make sure to import this key into your keyring. You can find it on the KMyMoney web-site. This time your data will not be encrypted with the KMyMoney recover key.").tqarg(RECOVER_KEY_ID), i18n("GPG-Key not found"));
encryptRecover = false;
}
}
TQStringList keys = TQStringList::split(",", keyList);
TQStringList::const_iterator it_s;
for(it_s = keys.begin(); it_s != keys.begin(); ++it_s) {
if(!KGPGFile::keyAvailable(*it_s)) {
KMessageBox::sorry(this, TQString("")+i18n("You have specified to encrypt your data for the user-id
%1.
Unfortunately, a valid key for this user-id was not found in your keyring. Please make sure to import a valid key for this user-id. This time, encryption is disabled.").tqarg(*it_s), i18n("GPG-Key not found"));
encryptedOk = false;
}
}
if(encryptedOk == true) {
TQString msg = TQString("") + i18n("You have configured to save your data in encrypted form using GPG. Please be aware, that this is a brand new feature which is yet untested. Make sure, you have the necessary understanding that you might loose all your data if you store it encrypted and cannot decrypt it later on! If unsure, answer No.");
if(KMessageBox::questionYesNo(this, msg, i18n("Store GPG encrypted"), KStdGuiItem::yes(), KStdGuiItem::no(), "StoreEncrypted") == KMessageBox::No) {
encryptedOk = false;
}
}
}
int tqmask = umask((~m_fmode) & 0777);
bool blocked = MyMoneyFile::instance()->signalsBlocked();
MyMoneyFile::instance()->blockSignals(true);
MyMoneyFileTransaction ft;
MyMoneyFile::instance()->deletePair("kmm-encryption-key");
if(!keyList.isEmpty() && encryptedOk == true && !plaintext ) {
qfile->close();
base++;
KGPGFile *kgpg = new KGPGFile(qfile->name());
if(kgpg) {
TQStringList keys = TQStringList::split(",", keyList);
TQStringList::const_iterator it_s;
for(it_s = keys.begin(); it_s != keys.end(); ++it_s) {
kgpg->addRecipient((*it_s).latin1());
}
if(encryptRecover) {
kgpg->addRecipient(RECOVER_KEY_ID);
}
MyMoneyFile::instance()->setValue("kmm-encryption-key", keyList);
}
statusDevice = dev = TQT_TQIODEVICE(kgpg);
if(!dev || !dev->open(IO_WriteOnly)) {
MyMoneyFile::instance()->blockSignals(blocked);
delete dev;
throw new MYMONEYEXCEPTION(i18n("Unable to open file '%1' for writing.").tqarg(qfile->name()));
}
} else if(!plaintext) {
base = KFilterBase::findFilterByMimeType( COMPRESSION_MIME_TYPE );
if(base) {
qfile->close();
base->setDevice(TQT_TQIODEVICE(qfile), false);
// we need to reopen the file to set the mode inside the filter stuff
dev = new KFilterDev(base, true);
if(!dev || !dev->open(IO_WriteOnly)) {
MyMoneyFile::instance()->blockSignals(blocked);
delete dev;
throw new MYMONEYEXCEPTION(i18n("Unable to open file '%1' for writing.").tqarg(qfile->name()));
}
statusDevice = base->device();
}
}
umask(tqmask);
ft.commit();
pWriter->setProgressCallback(&KMyMoneyView::progressCallback);
dev->resetqStatus();
pWriter->writeFile(dev, dynamic_cast (MyMoneyFile::instance()->storage()));
MyMoneyFile::instance()->blockSignals(blocked);
if(statusDevice->status() != IO_Ok) {
throw new MYMONEYEXCEPTION(i18n("Failure while writing to '%1'").tqarg(qfile->name()));
}
pWriter->setProgressCallback(0);
if(base != 0) {
dev->flush();
dev->close();
if(statusDevice->status() != IO_Ok) {
delete dev;
throw new MYMONEYEXCEPTION(i18n("Failure while writing to '%1'").tqarg(qfile->name()));
}
delete dev;
} else
qfile->close();
}
bool KMyMoneyView::saveFile(const KURL& url, const TQString& keyList)
{
TQString filename = url.path();
if (!fileOpen()) {
KMessageBox::error(this, i18n("Tried to access a file when it's not open"));
return false;
}
#if 0
if(KMessageBox::warningContinueCancel(this, i18n(
"Since this version of KMyMoney only writes data files in its new "
"format, files written with this version cannot be read by KMyMoney version 0.4. "
"If you still want to use older versions of KMyMoney with your data files, "
"please make sure you keep a backup-file of your finance data. "
"If you want to abort this operation, please press Cancel now"),
TQString(), KStdGuiItem::cont(), "WarningNewFileVersion0.5") == KMessageBox::Cancel)
return false;
#endif
emit kmmFilePlugin (preSave);
IMyMoneyStorageFormat* pWriter = NULL;
// If this file ends in ".ANON.XML" then this should be written using the
// anonymous writer.
bool plaintext = filename.right(4).lower() == ".xml";
if (filename.right(9).lower() == ".anon.xml")
{
pWriter = new MyMoneyStorageANON;
}
else
{
// only use XML writer. The binary format will be depreacated after 0.8
pWriter = new MyMoneyStorageXML;
}
// actually, url should be the parameter to this function
// but for now, this would involve too many changes
bool rc = true;
try {
if(! url.isValid()) {
throw new MYMONEYEXCEPTION(i18n("Malformed URL '%1'").tqarg(url.url()));
}
if(url.isLocalFile()) {
filename = url.path();
int fmode = 0600;
gid_t gid = static_cast(-1); // don't change the group id (see "man 2 chown")
TQFileInfo fi(filename);
if(fi.exists()) {
fmode |= fi.permission(TQFileInfo::ReadGroup) ? 040 : 0;
fmode |= fi.permission(TQFileInfo::WriteGroup) ? 020 : 0;
fmode |= fi.permission(TQFileInfo::ReadOther) ? 004 : 0;
fmode |= fi.permission(TQFileInfo::WriteOther) ? 002 : 0;
if(fi.groupId() != static_cast(-2))
gid = fi.groupId();
}
// create a new basic block here, so that the object qfile gets
// deleted, before we reach the chown() call
{
int tqmask = umask((~fmode) & 0777);
KSaveFile qfile(filename, fmode);
umask(tqmask);
if(qfile.status() == 0) {
try {
saveToLocalFile(qfile.file(), pWriter, plaintext, keyList);
} catch (MyMoneyException* e) {
qfile.abort();
delete e;
throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").tqarg(filename));
}
} else {
throw new MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'").tqarg(filename));
}
}
chown(filename, static_cast(-1), gid);
} else {
KTempFile tmpfile;
saveToLocalFile(tmpfile.file(), pWriter, plaintext, keyList);
if(!KIO::NetAccess::upload(tmpfile.name(), url, NULL))
throw new MYMONEYEXCEPTION(i18n("Unable to upload to '%1'").tqarg(url.url()));
tmpfile.unlink();
}
m_fileType = KmmXML;
} catch (MyMoneyException *e) {
KMessageBox::error(this, e->what());
delete e;
MyMoneyFile::instance()->setDirty();
rc = false;
}
delete pWriter;
emit kmmFilePlugin (postSave);
return rc;
}
bool KMyMoneyView::saveAsDatabase(const KURL& url)
{
bool rc = false;
if (!fileOpen()) {
KMessageBox::error(this, i18n("Tried to access a file when it's not open"));
return (rc);
}
MyMoneyStorageSql *writer = new MyMoneyStorageSql(dynamic_cast (MyMoneyFile::instance()->storage()), url);
bool canWrite = false;
switch (writer->open(url, IO_WriteOnly)) {
case 0:
canWrite = true;
break;
case -1: // dbase already has data, see if he wants to clear it out
if (KMessageBox::warningContinueCancel (0,
i18n("Database contains data which must be removed before using SaveAs.\n"
"Do you wish to continue?"), "Database not empty") == KMessageBox::Continue) {
if (writer->open(url, IO_WriteOnly, true) == 0) canWrite = true;
} else {
delete writer;
return false;
}
break;
}
if (canWrite) {
writer->setProgressCallback(&KMyMoneyView::progressCallback);
if (!writer->writeFile()) {
KMessageBox::detailedError (0,
i18n("An unrecoverable error occurred while writing to the database.\n"
"It may well be corrupt."),
writer->lastError().latin1(),
i18n("Database malfunction"));
rc = false;
}
writer->setProgressCallback(0);
rc = true;
} else {
KMessageBox::detailedError (this,
i18n("Can't open or create database %1\n"
"Retry SaveAsDatabase and click Help"
" for further info").tqarg(url.prettyURL()), writer->lastError());
}
delete writer;
return (rc);
}
bool KMyMoneyView::dirty(void)
{
if (!fileOpen())
return false;
return MyMoneyFile::instance()->dirty();
}
bool KMyMoneyView::startReconciliation(const MyMoneyAccount& account, const TQDate& reconciliationDate, const MyMoneyMoney& endingBalance)
{
bool ok = true;
// we cannot reconcile standard accounts
if(MyMoneyFile::instance()->isStandardAccount(account.id()))
ok = false;
// check if we can reconcile this account
// it makes sense for asset and liability accounts only
if(ok == true) {
if(account.isAssetLiability()) {
showPage(pageIndex(m_ledgerViewFrame));
// prepare reconciliation mode
emit reconciliationStarts(account, reconciliationDate, endingBalance);
} else {
ok = false;
}
}
return ok;
}
void KMyMoneyView::finishReconciliation(const MyMoneyAccount& /* account */)
{
emit reconciliationStarts(MyMoneyAccount(), TQDate(), MyMoneyMoney());
}
void KMyMoneyView::newFile(void)
{
closeFile();
m_fileType = KmmXML; // assume native type until saved
m_fileOpen = true;
}
void KMyMoneyView::slotSetBaseCurrency(const MyMoneySecurity& baseCurrency)
{
if(!baseCurrency.id().isEmpty()) {
if(baseCurrency.id() != MyMoneyFile::instance()->baseCurrency().id()) {
MyMoneyFileTransaction ft;
try {
MyMoneyFile::instance()->setBaseCurrency(baseCurrency);
ft.commit();
} catch(MyMoneyException *e) {
KMessageBox::sorry(this, i18n("Cannot set %1 as base currency: %2").tqarg(baseCurrency.name()).tqarg(e->what()), i18n("Set base currency"));
delete e;
}
}
}
}
void KMyMoneyView::selectBaseCurrency(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
// check if we have a base currency. If not, we need to select one
if(file->baseCurrency().id().isEmpty()) {
KCurrencyEditDlg dlg(this, "CurrencyEditDlg");
connect(&dlg, TQT_SIGNAL(selectBaseCurrency(const MyMoneySecurity&)), this, TQT_SLOT(slotSetBaseCurrency(const MyMoneySecurity&)));
dlg.exec();
}
if(!file->baseCurrency().id().isEmpty()) {
// check that all accounts have a currency
TQValueList list;
file->accountList(list);
TQValueList::Iterator it;
// don't forget those standard accounts
list << file->asset();
list << file->liability();
list << file->income();
list << file->expense();
list << file->equity();
for(it = list.begin(); it != list.end(); ++it) {
if((*it).currencyId().isEmpty() || (*it).currencyId().length() == 0) {
(*it).setCurrencyId(file->baseCurrency().id());
MyMoneyFileTransaction ft;
try {
file->modifyAccount(*it);
ft.commit();
} catch(MyMoneyException *e) {
qDebug("Unable to setup base currency in account %s (%s): %s", (*it).name().latin1(), (*it).id().data(), e->what().latin1());
delete e;
}
}
}
}
}
void KMyMoneyView::loadDefaultCurrency(const MyMoneySecurity& currency, const bool create)
{
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneySecurity sec;
MyMoneyFileTransaction ft;
try {
sec = file->currency(currency.id());
if(sec.name() != currency.name()) {
sec.setName(currency.name());
file->modifyCurrency(sec);
}
ft.commit();
} catch (MyMoneyException* e) {
delete e;
try {
if(create) {
file->addCurrency(currency);
}
ft.commit();
} catch (MyMoneyException* e) {
qDebug("Error %s loading default currency", e->what().data());
delete e;
}
}
}
void KMyMoneyView::loadDefaultCurrencies(void)
{
// more information can be obtained from http://en.wikipedia.org/wiki/Currency_codes
bool create = MyMoneyFile::instance()->currencyList().count() == 0;
loadDefaultCurrency(MyMoneySecurity("AFA", i18n("Afghanistan Afghani")), create);
loadDefaultCurrency(MyMoneySecurity("ALL", i18n("Albanian Lek")), create);
loadDefaultCurrency(MyMoneySecurity("ANG", i18n("Netherland Antillian Guilder")), create);
loadDefaultCurrency(MyMoneySecurity("DZD", i18n("Algerian Dinar")), create);
loadDefaultCurrency(MyMoneySecurity("ADF", i18n("Andorran Franc")), create);
loadDefaultCurrency(MyMoneySecurity("ADP", i18n("Andorran Peseta")), create);
loadDefaultCurrency(MyMoneySecurity("AON", i18n("Angolan New Kwanza")), create);
loadDefaultCurrency(MyMoneySecurity("ARS", i18n("Argentine Peso"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("AWG", i18n("Aruban Florin")), create);
loadDefaultCurrency(MyMoneySecurity("AUD", i18n("Australian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("AZM", i18n("Azerbaijani Manat")), create);
loadDefaultCurrency(MyMoneySecurity("BSD", i18n("Bahamian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("BHD", i18n("Bahraini Dinar"), "BHD", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("BDT", i18n("Bangladeshi Taka")), create);
loadDefaultCurrency(MyMoneySecurity("BBD", i18n("Barbados Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("BYR", i18n("Belarussian Ruble"), "BYR", 1, 1), create);
loadDefaultCurrency(MyMoneySecurity("BZD", i18n("Belize Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("BMD", i18n("Bermudian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("BTN", i18n("Bhutan Ngultrum")), create);
loadDefaultCurrency(MyMoneySecurity("BOB", i18n("Bolivian Boliviano")), create);
loadDefaultCurrency(MyMoneySecurity("BAM", i18n("Bosnian Convertible Mark")), create);
loadDefaultCurrency(MyMoneySecurity("BWP", i18n("Botswana Pula")), create);
loadDefaultCurrency(MyMoneySecurity("BRL", i18n("Brazilian Real"), "R$"), create);
loadDefaultCurrency(MyMoneySecurity("GBP", i18n("British Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("BND", i18n("Brunei Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("BGL", i18n("Bulgarian Lev")), create);
loadDefaultCurrency(MyMoneySecurity("BIF", i18n("Burundi Franc")), create);
loadDefaultCurrency(MyMoneySecurity("XAF", i18n("CFA Franc BEAC")), create);
loadDefaultCurrency(MyMoneySecurity("XOF", i18n("CFA Franc BCEAO")), create);
loadDefaultCurrency(MyMoneySecurity("XPF", i18n("CFP Franc Pacifique"), "F", 1, 1, 100), create);
loadDefaultCurrency(MyMoneySecurity("KHR", i18n("Cambodia Riel")), create);
loadDefaultCurrency(MyMoneySecurity("CAD", i18n("Canadian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("CVE", i18n("Cape Verde Escudo")), create);
loadDefaultCurrency(MyMoneySecurity("KYD", i18n("Cayman Islands Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("CLP", i18n("Chilean Peso")), create);
loadDefaultCurrency(MyMoneySecurity("CNY", i18n("Chinese Yuan Renminbi")), create);
loadDefaultCurrency(MyMoneySecurity("COP", i18n("Colombian Peso")), create);
loadDefaultCurrency(MyMoneySecurity("KMF", i18n("Comoros Franc")), create);
loadDefaultCurrency(MyMoneySecurity("CRC", i18n("Costa Rican Colon"), TQChar(0x20A1)), create);
loadDefaultCurrency(MyMoneySecurity("HRK", i18n("Croatian Kuna")), create);
loadDefaultCurrency(MyMoneySecurity("CUP", i18n("Cuban Peso")), create);
loadDefaultCurrency(MyMoneySecurity("CZK", i18n("Czech Koruna")), create);
loadDefaultCurrency(MyMoneySecurity("DKK", i18n("Danish Krone"), "kr"), create);
loadDefaultCurrency(MyMoneySecurity("DJF", i18n("Djibouti Franc")), create);
loadDefaultCurrency(MyMoneySecurity("DOP", i18n("Dominican Peso")), create);
loadDefaultCurrency(MyMoneySecurity("XCD", i18n("East Caribbean Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("EGP", i18n("Egyptian Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("SVC", i18n("El Salvador Colon")), create);
loadDefaultCurrency(MyMoneySecurity("ERN", i18n("Eritrean Nakfa")), create);
loadDefaultCurrency(MyMoneySecurity("EEK", i18n("Estonian Kroon")), create);
loadDefaultCurrency(MyMoneySecurity("ETB", i18n("Ethiopian Birr")), create);
loadDefaultCurrency(MyMoneySecurity("EUR", i18n("Euro"), TQChar(0x20ac)), true);
loadDefaultCurrency(MyMoneySecurity("FKP", i18n("Falkland Islands Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("FJD", i18n("Fiji Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("GMD", i18n("Gambian Dalasi")), create);
loadDefaultCurrency(MyMoneySecurity("GEL", i18n("Georgian Lari")), create);
loadDefaultCurrency(MyMoneySecurity("GHC", i18n("Ghanaian Cedi")), create);
loadDefaultCurrency(MyMoneySecurity("GIP", i18n("Gibraltar Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("GTQ", i18n("Guatemalan Quetzal")), create);
loadDefaultCurrency(MyMoneySecurity("GWP", i18n("Guinea-Bissau Peso")), create);
loadDefaultCurrency(MyMoneySecurity("GYD", i18n("Guyanan Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("HTG", i18n("Haitian Gourde")), create);
loadDefaultCurrency(MyMoneySecurity("HNL", i18n("Honduran Lempira")), create);
loadDefaultCurrency(MyMoneySecurity("HKD", i18n("Hong Kong Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("HUF", i18n("Hungarian Forint"), "HUF", 1, 1, 100), create);
loadDefaultCurrency(MyMoneySecurity("ISK", i18n("Iceland Krona")), create);
loadDefaultCurrency(MyMoneySecurity("INR", i18n("Indian Rupee"), TQChar(0x20A8)), create);
loadDefaultCurrency(MyMoneySecurity("IDR", i18n("Indonesian Rupiah"), "IDR", 100, 1), create);
loadDefaultCurrency(MyMoneySecurity("IRR", i18n("Iranian Rial"), "IRR", 1, 1), create);
loadDefaultCurrency(MyMoneySecurity("IQD", i18n("Iraqi Dinar"), "IQD", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("ILS", i18n("Israeli New Shekel"), TQChar(0x20AA)), create);
loadDefaultCurrency(MyMoneySecurity("JMD", i18n("Jamaican Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("JPY", i18n("Japanese Yen"), TQChar(0x00A5), 100, 1), create);
loadDefaultCurrency(MyMoneySecurity("JOD", i18n("Jordanian Dinar"), "JOD", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("KZT", i18n("Kazakhstan Tenge")), create);
loadDefaultCurrency(MyMoneySecurity("KES", i18n("Kenyan Shilling")), create);
loadDefaultCurrency(MyMoneySecurity("KWD", i18n("Kuwaiti Dinar"), "KWD", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("KGS", i18n("Kyrgyzstan Som")), create);
loadDefaultCurrency(MyMoneySecurity("LAK", i18n("Laos Kip"), TQChar(0x20AD)), create);
loadDefaultCurrency(MyMoneySecurity("LVL", i18n("Latvian Lats")), create);
loadDefaultCurrency(MyMoneySecurity("LBP", i18n("Lebanese Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("LSL", i18n("Lesotho Loti")), create);
loadDefaultCurrency(MyMoneySecurity("LRD", i18n("Liberian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("LYD", i18n("Libyan Dinar"), "LYD", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("LTL", i18n("Lithuanian Litas")), create);
loadDefaultCurrency(MyMoneySecurity("MOP", i18n("Macau Pataca")), create);
loadDefaultCurrency(MyMoneySecurity("MKD", i18n("Macedonian Denar")), create);
loadDefaultCurrency(MyMoneySecurity("MGF", i18n("Malagasy Franc"), "MGF", 500, 500), create);
loadDefaultCurrency(MyMoneySecurity("MWK", i18n("Malawi Kwacha")), create);
loadDefaultCurrency(MyMoneySecurity("MYR", i18n("Malaysian Ringgit")), create);
loadDefaultCurrency(MyMoneySecurity("MVR", i18n("Maldive Rufiyaa")), create);
loadDefaultCurrency(MyMoneySecurity("MLF", i18n("Mali Republic Franc")), create);
loadDefaultCurrency(MyMoneySecurity("MRO", i18n("Mauritanian Ouguiya"), "MRO", 5, 5), create);
loadDefaultCurrency(MyMoneySecurity("MUR", i18n("Mauritius Rupee")), create);
loadDefaultCurrency(MyMoneySecurity("MXN", i18n("Mexican Peso"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("MDL", i18n("Moldavian Leu")), create);
loadDefaultCurrency(MyMoneySecurity("MNT", i18n("Mongolian Tugrik"), TQChar(0x20AE)), create);
loadDefaultCurrency(MyMoneySecurity("MAD", i18n("Moroccan Dirham")), create);
loadDefaultCurrency(MyMoneySecurity("MZM", i18n("Mozambique Metical")), create);
loadDefaultCurrency(MyMoneySecurity("MMK", i18n("Myanmar Kyat")), create);
loadDefaultCurrency(MyMoneySecurity("NAD", i18n("Namibian Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("NPR", i18n("Nepalese Rupee")), create);
loadDefaultCurrency(MyMoneySecurity("NZD", i18n("New Zealand Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("NIC", i18n("Nicaraguan Cordoba Oro")), create);
loadDefaultCurrency(MyMoneySecurity("NGN", i18n("Nigerian Naira"), TQChar(0x20A6)), create);
loadDefaultCurrency(MyMoneySecurity("KPW", i18n("North Korean Won"), TQChar(0x20A9)), create);
loadDefaultCurrency(MyMoneySecurity("NOK", i18n("Norwegian Kroner"), "kr"), create);
loadDefaultCurrency(MyMoneySecurity("OMR", i18n("Omani Rial"), "OMR", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("PKR", i18n("Pakistan Rupee")), create);
loadDefaultCurrency(MyMoneySecurity("PAB", i18n("Panamanian Balboa")), create);
loadDefaultCurrency(MyMoneySecurity("PGK", i18n("Papua New Guinea Kina")), create);
loadDefaultCurrency(MyMoneySecurity("PYG", i18n("Paraguay Guarani")), create);
loadDefaultCurrency(MyMoneySecurity("PEN", i18n("Peruvian Nuevo Sol")), create);
loadDefaultCurrency(MyMoneySecurity("PHP", i18n("Philippine Peso"), TQChar(0x20B1)), create);
loadDefaultCurrency(MyMoneySecurity("PLN", i18n("Polish Zloty")), create);
loadDefaultCurrency(MyMoneySecurity("TQAR", i18n("Qatari Rial")), create);
loadDefaultCurrency(MyMoneySecurity("RON", i18n("Romanian Leu (new)")), true);
loadDefaultCurrency(MyMoneySecurity("RUB", i18n("Russian Ruble")), true);
loadDefaultCurrency(MyMoneySecurity("RWF", i18n("Rwanda Franc")), create);
loadDefaultCurrency(MyMoneySecurity("WST", i18n("Samoan Tala")), create);
loadDefaultCurrency(MyMoneySecurity("STD", i18n("Sao Tome and Principe Dobra")), create);
loadDefaultCurrency(MyMoneySecurity("SAR", i18n("Saudi Riyal")), create);
loadDefaultCurrency(MyMoneySecurity("SCR", i18n("Seychelles Rupee")), create);
loadDefaultCurrency(MyMoneySecurity("SLL", i18n("Sierra Leone Leone")), create);
loadDefaultCurrency(MyMoneySecurity("SGD", i18n("Singapore Dollar"), "$"), create);
// loadDefaultCurrency(MyMoneySecurity("SKK", i18n("Slovak Koruna")), create);
// loadDefaultCurrency(MyMoneySecurity("SIT", i18n("Slovenian Tolar")), create);
loadDefaultCurrency(MyMoneySecurity("SBD", i18n("Solomon Islands Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("SOS", i18n("Somali Shilling")), create);
loadDefaultCurrency(MyMoneySecurity("ZAR", i18n("South African Rand")), create);
loadDefaultCurrency(MyMoneySecurity("KRW", i18n("South Korean Won"), TQChar(0x20A9)), create);
loadDefaultCurrency(MyMoneySecurity("LKR", i18n("Sri Lanka Rupee")), create);
loadDefaultCurrency(MyMoneySecurity("SHP", i18n("St. Helena Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("SDD", i18n("Sudanese Dinar")), create);
loadDefaultCurrency(MyMoneySecurity("SRG", i18n("Suriname Guilder")), create);
loadDefaultCurrency(MyMoneySecurity("SZL", i18n("Swaziland Lilangeni")), create);
loadDefaultCurrency(MyMoneySecurity("SEK", i18n("Swedish Krona")), create);
loadDefaultCurrency(MyMoneySecurity("CHF", i18n("Swiss Franc"), "SFr"), create);
loadDefaultCurrency(MyMoneySecurity("SYP", i18n("Syrian Pound"), TQChar(0x00A3)), create);
loadDefaultCurrency(MyMoneySecurity("TWD", i18n("Taiwan Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("TJS", i18n("Tajikistan Somani")), create);
loadDefaultCurrency(MyMoneySecurity("TZS", i18n("Tanzanian Shilling")), create);
loadDefaultCurrency(MyMoneySecurity("THB", i18n("Thai Baht"), TQChar(0x0E3F)), create);
loadDefaultCurrency(MyMoneySecurity("TOP", i18n("Tongan Pa'anga")), create);
loadDefaultCurrency(MyMoneySecurity("TTD", i18n("Trinidad and Tobago Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("TND", i18n("Tunisian Dinar"), "TND", 1000, 1000), create);
loadDefaultCurrency(MyMoneySecurity("TRY", i18n("Turkish Lira (new)"), "YTL"), true);
loadDefaultCurrency(MyMoneySecurity("TMM", i18n("Turkmenistan Manat")), create);
loadDefaultCurrency(MyMoneySecurity("USD", i18n("US Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("UGX", i18n("Uganda Shilling")), create);
loadDefaultCurrency(MyMoneySecurity("UAH", i18n("Ukraine Hryvnia")), create);
loadDefaultCurrency(MyMoneySecurity("AED", i18n("United Arab Emirates Dirham")), create);
loadDefaultCurrency(MyMoneySecurity("UYU", i18n("Uruguayan Peso")), create);
loadDefaultCurrency(MyMoneySecurity("UZS", i18n("Uzbekistani Sum")), create);
loadDefaultCurrency(MyMoneySecurity("VUV", i18n("Vanuatu Vatu")), create);
loadDefaultCurrency(MyMoneySecurity("VEB", i18n("Venezuelan Bolivar")), create);
loadDefaultCurrency(MyMoneySecurity("VND", i18n("Vietnamese Dong"), TQChar(0x20AB)), create);
loadDefaultCurrency(MyMoneySecurity("YUM", i18n("Yugoslav Dinar")), create);
loadDefaultCurrency(MyMoneySecurity("ZMK", i18n("Zambian Kwacha")), create);
loadDefaultCurrency(MyMoneySecurity("ZWD", i18n("Zimbabwe Dollar"), "$"), create);
loadDefaultCurrency(MyMoneySecurity("XAU", i18n("Gold"), "XAU", 1, 1000000), create);
loadDefaultCurrency(MyMoneySecurity("XPD", i18n("Palladium"), "XPD", 1, 1000000), create);
loadDefaultCurrency(MyMoneySecurity("XPT", i18n("Platinum"), "XPT", 1, 1000000), create);
loadDefaultCurrency(MyMoneySecurity("XAG", i18n("Silver"), "XAG", 1, 1000000), create);
}
void KMyMoneyView::loadAncientCurrency(const TQString& id, const TQString& name, const TQString& sym, const TQDate& date, const MyMoneyMoney& rate, const TQString& newId, const int partsPerUnit, const int smallestCashFraction, const int smallestAccountFraction)
{
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneyPrice price(id, newId, date, rate, "KMyMoney");
MyMoneyFileTransaction ft;
try {
// make sure if entry exists
file->currency(id);
// make sure we have the right price
if(file->price(id, newId, date, true) != price) {
file->addPrice(price);
}
ft.commit();
} catch(MyMoneyException *e) {
delete e;
try {
file->addCurrency(MyMoneySecurity(id, name, sym, partsPerUnit, smallestCashFraction, smallestAccountFraction));
if(date.isValid()) {
file->addPrice(price);
}
ft.commit();
} catch(MyMoneyException *e) {
qDebug("Error loading currency: %s", e->what().data());
delete e;
}
}
}
void KMyMoneyView::loadAncientCurrencies(void)
{
loadAncientCurrency("ATS", i18n("Austrian Schilling"), "ÖS", TQDate(1998,12,31), MyMoneyMoney(10000, 137603), "EUR");
loadAncientCurrency("DEM", i18n("German Mark"), "DM", TQDate(1998,12,31), MyMoneyMoney(100000, 195583), "EUR");
loadAncientCurrency("FRF", i18n("French Franc"), "FF", TQDate(1998,12,31), MyMoneyMoney(100000, 655957), "EUR");
loadAncientCurrency("ITL", i18n("Italian Lira"), TQChar(0x20A4), TQDate(1998,12,31), MyMoneyMoney(100, 193627), "EUR");
loadAncientCurrency("ESP", i18n("Spanish Peseta"), TQString(), TQDate(1998,12,31), MyMoneyMoney(1000, 166386), "EUR");
loadAncientCurrency("NLG", i18n("Dutch Guilder"), TQString(), TQDate(1998,12,31), MyMoneyMoney(100000, 220371), "EUR");
loadAncientCurrency("BEF", i18n("Belgian Franc"), "Fr", TQDate(1998,12,31), MyMoneyMoney(10000, 403399), "EUR");
loadAncientCurrency("LUF", i18n("Luxembourg Franc"), "Fr", TQDate(1998,12,31), MyMoneyMoney(10000, 403399), "EUR");
loadAncientCurrency("PTE", i18n("Portuguese Escudo"), TQString(), TQDate(1998,12,31), MyMoneyMoney(1000, 200482), "EUR");
loadAncientCurrency("IEP", i18n("Irish Pound"), TQChar(0x00A3), TQDate(1998,12,31), MyMoneyMoney(1000000, 787564), "EUR");
loadAncientCurrency("FIM", i18n("Finnish Markka"), TQString(), TQDate(1998,12,31), MyMoneyMoney(100000, 594573), "EUR");
loadAncientCurrency("GRD", i18n("Greek Drachma"), TQChar(0x20AF), TQDate(1998,12,31), MyMoneyMoney(100, 34075), "EUR");
loadAncientCurrency("ROL", i18n("Romanian Leu"), "ROL", TQDate(2005,6,30), MyMoneyMoney(1, 10000), "RON");
loadAncientCurrency("RUR", i18n("Russian Ruble (old)"), "RUR", TQDate(1998, 1, 1), MyMoneyMoney(1, 1000), "RUB");
loadAncientCurrency("SIT", i18n("Slovenian Tolar"), "SIT", TQDate(2006,12,31), MyMoneyMoney(100, 23964), "EUR");
// Source: http://www.tf-portfoliosolutions.net/products/turkishlira.aspx
loadAncientCurrency("TRL", i18n("Turkish Lira"), "TL", TQDate(2004,12,31), MyMoneyMoney(1,1000000), "TRY");
// Source: http://www.focus.de/finanzen/news/malta-und-zypern_aid_66058.html
loadAncientCurrency("MTL", i18n("Maltese Lira"), "MTL", TQDate(2008,1,1), MyMoneyMoney(429300,1000000), "EUR");
loadAncientCurrency("CYP", i18n("Cyprus Pound"), TQString("C%1").tqarg(TQChar(0x00A3)), TQDate(2008,1,1), MyMoneyMoney(585274,1000000), "EUR");
// Source: http://www.focus.de/finanzen/news/waehrungszone-slowakei-ist-neuer-euro-staat_aid_359025.html
loadAncientCurrency("SKK", i18n("Slovak Koruna"), "SKK", TQDate(2008,12,31), MyMoneyMoney(1000,30126), "EUR");
}
void KMyMoneyView::viewUp(void)
{
if (!fileOpen())
return;
}
void KMyMoneyView::viewAccountList(const TQString& /*selectAccount*/)
{
if(pageIndex(m_accountsViewFrame) != activePageIndex())
showPage(1);
m_accountsView->show();
}
void KMyMoneyView::slotRefreshViews()
{
// turn off sync between ledger and investment view
disconnect(m_investmentView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), m_ledgerView, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
disconnect(m_ledgerView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), m_investmentView, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
// TODO turn sync between ledger and investment view if selected by user
if(KMyMoneyGlobalSettings::syncLedgerInvestment()) {
connect(m_investmentView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), m_ledgerView, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
connect(m_ledgerView, TQT_SIGNAL(accountSelected(const MyMoneyObject&)), m_investmentView, TQT_SLOT(slotSelectAccount(const MyMoneyObject&)));
}
showTitleBar(KMyMoneyGlobalSettings::showTitleBar());
m_accountsView->slotLoadAccounts();
m_institutionsView->slotLoadAccounts();
m_categoriesView->slotLoadAccounts();
m_payeesView->slotLoadPayees();
m_ledgerView->slotLoadView();
m_budgetView->slotRefreshView();
m_homeView->slotLoadView();
m_investmentView->slotLoadView();
m_reportsView->slotLoadView();
m_forecastView->slotLoadForecast();
m_scheduledView->slotReloadView();
}
void KMyMoneyView::slotShowTransactionDetail(bool detailed)
{
KMyMoneyGlobalSettings::setShowRegisterDetailed(detailed);
slotRefreshViews();
}
void KMyMoneyView::progressCallback(int current, int total, const TQString& msg)
{
kmymoney2->progressCallback(current, total, msg);
}
void KMyMoneyView::slotRememberPage(TQWidget* w)
{
KConfig *config = KGlobal::config();
config->setGroup("Last Use Settings");
config->writeEntry("LastViewSelected", pageIndex(w));
config->sync();
}
/* DO NOT ADD code to this function or any of it's called ones.
Instead, create a new function, fixFile_n, and modify the initializeStorage()
logic above to call it */
void KMyMoneyView::fixFile_2(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneyTransactionFilter filter;
filter.setReportAllSplits( false );
TQValueList transactionList;
file->transactionList(transactionList, filter);
// scan the transactions and modify transactions with two splits
// which reference an account and a category to have the memo text
// of the account.
TQValueList::Iterator it_t;
int count = 0;
for(it_t = transactionList.begin(); it_t != transactionList.end(); ++it_t) {
if((*it_t).splitCount() == 2) {
TQString accountId;
TQString categoryId;
TQString accountMemo;
TQString categoryMemo;
const TQValueList& splits = (*it_t).splits();
TQValueList::const_iterator it_s;
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
MyMoneyAccount acc = file->account((*it_s).accountId());
if(acc.isIncomeExpense()) {
categoryId = (*it_s).id();
categoryMemo = (*it_s).memo();
} else {
accountId = (*it_s).id();
accountMemo = (*it_s).memo();
}
}
if(!accountId.isEmpty() && !categoryId.isEmpty()
&& accountMemo != categoryMemo) {
MyMoneyTransaction t(*it_t);
MyMoneySplit s(t.splitById(categoryId));
s.setMemo(accountMemo);
t.modifySplit(s);
file->modifyTransaction(t);
++count;
}
}
}
qDebug("%d transactions fixed in fixFile_2", count);
}
void KMyMoneyView::fixFile_1(void)
{
// we need to fix reports. If the account filter list contains
// investment accounts, we need to add the stock accounts to the list
// as well if we don't have the expert mode enabled
if(!KMyMoneyGlobalSettings::expertMode()) {
try {
TQValueList reports = MyMoneyFile::instance()->reportList();
TQValueList::iterator it_r;
for(it_r = reports.begin(); it_r != reports.end(); ++it_r) {
TQStringList list;
(*it_r).accounts(list);
TQStringList missing;
TQStringList::const_iterator it_a, it_b;
for(it_a = list.begin(); it_a != list.end(); ++it_a) {
MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
if(acc.accountType() == MyMoneyAccount::Investment) {
for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
if(!list.contains(*it_b)) {
missing.append(*it_b);
}
}
}
}
if(!missing.isEmpty()) {
(*it_r).addAccount(missing);
MyMoneyFile::instance()->modifyReport(*it_r);
}
}
} catch(MyMoneyException* e) {
delete e;
}
}
}
#if 0
if(!m_accountsView->allItemsSelected()) {
// retrieve a list of selected accounts
TQStringList list;
m_accountsView->selectedItems(list);
// if we're not in expert mode, we need to make sure
// that all stock accounts for the selected investment
// account are also selected
if(!KMyMoneyGlobalSettings::expertMode()) {
TQStringList missing;
TQStringList::const_iterator it_a, it_b;
for(it_a = list.begin(); it_a != list.end(); ++it_a) {
MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a);
if(acc.accountType() == MyMoneyAccount::Investment) {
for(it_b = acc.accountList().begin(); it_b != acc.accountList().end(); ++it_b) {
if(!list.contains(*it_b)) {
missing.append(*it_b);
}
}
}
}
list += missing;
}
m_filter.addAccount(list);
}
#endif
void KMyMoneyView::fixFile_0(void)
{
/* (Ace) I am on a crusade against file fixups. Whenever we have to fix the
* file, it is really a warning. So I'm going to print a debug warning, and
* then go track them down when I see them to figure out how they got saved
* out needing fixing anyway.
*/
MyMoneyFile* file = MyMoneyFile::instance();
TQValueList accountList;
file->accountList(accountList);
::timetrace("Have account list");
TQValueList::Iterator it_a;
TQValueList scheduleList = file->scheduleList();
::timetrace("Have schedule list");
TQValueList::Iterator it_s;
MyMoneyAccount equity = file->equity();
MyMoneyAccount asset = file->asset();
bool equityListEmpty = equity.accountList().count() == 0;
::timetrace("Fix accounts start");
for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
if((*it_a).accountType() == MyMoneyAccount::Loan
|| (*it_a).accountType() == MyMoneyAccount::AssetLoan) {
fixLoanAccount_0(*it_a);
}
// until early before 0.8 release, the equity account was not saved to
// the file. If we have an equity account with no sub-accounts but
// find and equity account that has equity() as it's tqparent, we reparent
// this account. Need to move it to asset() first, because otherwise
// MyMoneyFile::reparent would act as NOP.
if(equityListEmpty && (*it_a).accountType() == MyMoneyAccount::Equity) {
if((*it_a).parentAccountId() == equity.id()) {
MyMoneyAccount acc = *it_a;
// tricky, force tqparent account to be empty so that we really
// can re-tqparent it
acc.setParentAccountId(TQString());
file->reparentAccount(acc, equity);
kdDebug(2) << __func__ << " fixed account " << acc.id() << " reparented to " << equity.id() << endl;
}
}
}
::timetrace("Fix schedules start");
for(it_s = scheduleList.begin(); it_s != scheduleList.end(); ++it_s) {
fixSchedule_0(*it_s);
}
::timetrace("Fix transactions start");
fixTransactions_0();
::timetrace("Fix transactions done");
}
void KMyMoneyView::fixSchedule_0(MyMoneySchedule sched)
{
MyMoneyTransaction t = sched.transaction();
TQValueList splitList = t.splits();
TQValueList::ConstIterator it_s;
bool updated = false;
try {
// Check if the splits contain valid data and set it to
// be valid.
for(it_s = splitList.begin(); it_s != splitList.end(); ++it_s) {
// the first split is always the account on which this transaction operates
// and if the transaction commodity is not set, we take this
if(it_s == splitList.begin() && t.commodity().isEmpty()) {
kdDebug(2) << __func__ << " " << t.id() << " has no commodity" << endl;
try {
MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
t.setCommodity(acc.currencyId());
updated = true;
} catch(MyMoneyException *e) {
delete e;
}
}
// make sure the account exists. If not, remove the split
try {
MyMoneyFile::instance()->account((*it_s).accountId());
} catch(MyMoneyException *e) {
kdDebug(2) << __func__ << " " << sched.id() << " " << (*it_s).id() << " removed, because account '" << (*it_s).accountId() << "' does not exist." << endl;
t.removeSplit(*it_s);
updated = true;
delete e;
}
if((*it_s).reconcileFlag() != MyMoneySplit::NotReconciled) {
kdDebug(2) << __func__ << " " << sched.id() << " " << (*it_s).id() << " should be 'not reconciled'" << endl;
MyMoneySplit split = *it_s;
split.setReconcileDate(TQDate());
split.setReconcileFlag(MyMoneySplit::NotReconciled);
t.modifySplit(split);
updated = true;
}
// the schedule logic used to operate only on the value field.
// This is now obsolete.
if((*it_s).shares().isZero() && !(*it_s).value().isZero()) {
MyMoneySplit split = *it_s;
split.setShares(split.value());
t.modifySplit(split);
updated = true;
}
}
// If there have been changes, update the schedule and
// the engine data.
if(updated) {
sched.setTransaction(t);
MyMoneyFile::instance()->modifySchedule(sched);
}
} catch(MyMoneyException *e) {
qWarning("Unable to update broken schedule: %s", e->what().latin1());
delete e;
}
}
void KMyMoneyView::fixLoanAccount_0(MyMoneyAccount acc)
{
if(acc.value("final-payment").isEmpty()
|| acc.value("term").isEmpty()
|| acc.value("periodic-payment").isEmpty()
|| acc.value("loan-amount").isEmpty()
|| acc.value("interest-calculation").isEmpty()
|| acc.value("schedule").isEmpty()
|| acc.value("fixed-interest").isEmpty()) {
KMessageBox::information(this,
i18n("The account \"%1\" was previously created as loan account but some information "
"is missing. The new loan wizard will be started to collect all relevant "
"information. Please use a KMyMoney version >= 0.8.7 and < 0.9 to correct the problem."
).tqarg(acc.name()),
i18n("Account problem"));
throw new MYMONEYEXCEPTION("Fix LoanAccount0 not supported anymore");
}
}
void KMyMoneyView::createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount)
{
// Add the schedule only if one exists
//
// Remember to modify the first split to reference the newly created account
if (!newSchedule.name().isEmpty())
{
MyMoneyFileTransaction ft;
try
{
// We assume at least 2 splits in the transaction
MyMoneyTransaction t = newSchedule.transaction();
if(t.splitCount() < 2) {
throw new MYMONEYEXCEPTION("Transaction for schedule has less than 2 splits!");
}
// now search the split that does not have an account reference
// and set it up to be the one of the account we just added
// to the account pool. Note: the schedule code used to leave
// this always the first split, but the loan code leaves it as
// the second one. So I thought, searching is a good alternative ....
TQValueList::ConstIterator it_s;
for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
if((*it_s).accountId().isEmpty()) {
MyMoneySplit s = (*it_s);
s.setAccountId(newAccount.id());
t.modifySplit(s);
break;
}
}
newSchedule.setTransaction(t);
MyMoneyFile::instance()->addSchedule(newSchedule);
// in case of a loan account, we keep a reference to this
// schedule in the account
if(newAccount.isLoan()) {
newAccount.setValue("schedule", newSchedule.id());
MyMoneyFile::instance()->modifyAccount(newAccount);
}
ft.commit();
}
catch (MyMoneyException *e)
{
KMessageBox::information(this, i18n("Unable to add schedule: "), e->what());
delete e;
}
}
}
void KMyMoneyView::fixTransactions_0(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
#if 0
::timetrace("Start alloc memory");
int * p = new int [10000];
delete p;
::timetrace("Done alloc memory");
#endif
::timetrace("fixTransactions: get schedule list");
TQValueList scheduleList = file->scheduleList();
::timetrace("fixTransactions: get transaction list");
MyMoneyTransactionFilter filter;
filter.setReportAllSplits( false );
TQValueList transactionList;
file->transactionList(transactionList, filter);
::timetrace("fixTransactions: have list");
TQValueList::Iterator it_x;
TQStringList interestAccounts;
KMSTATUS(i18n("Fix transactions"));
kmymoney2->slotStatusProgressBar(0, scheduleList.count() + transactionList.count());
int cnt = 0;
// scan the schedules to find interest accounts
for(it_x = scheduleList.begin(); it_x != scheduleList.end(); ++it_x) {
MyMoneyTransaction t = (*it_x).transaction();
TQValueList::ConstIterator it_s;
TQStringList accounts;
bool hasDuplicateAccounts = false;
for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
if(accounts.contains((*it_s).accountId())) {
hasDuplicateAccounts = true;
kdDebug(2) << __func__ << " " << t.id() << " has multiple splits with account " << (*it_s).accountId() << endl;
} else {
accounts << (*it_s).accountId();
}
if((*it_s).action() == MyMoneySplit::ActionInterest) {
if(interestAccounts.contains((*it_s).accountId()) == 0) {
interestAccounts << (*it_s).accountId();
}
}
}
if(hasDuplicateAccounts) {
fixDuplicateAccounts_0(t);
}
++cnt;
if(!(cnt % 10))
kmymoney2->slotStatusProgressBar(cnt);
}
::timetrace("fixTransactions: start loop");
// scan the transactions and modify loan transactions
TQValueList::Iterator it_t;
for(it_t = transactionList.begin(); it_t != transactionList.end(); ++it_t) {
const char *defaultAction = 0;
TQValueList splits = (*it_t).splits();
TQValueList::Iterator it_s;
TQStringList accounts;
// check if base commodity is set. if not, set baseCurrency
if((*it_t).commodity().isEmpty()) {
kdDebug(2) << __func__ << " " << (*it_t).id() << " has no base currency" << endl;
(*it_t).setCommodity(file->baseCurrency().id());
file->modifyTransaction(*it_t);
}
bool isLoan = false;
// Determine default action
if((*it_t).splitCount() == 2) {
// check for transfer
int accountCount = 0;
MyMoneyMoney val;
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
MyMoneyAccount acc = file->account((*it_s).accountId());
if(acc.accountGroup() == MyMoneyAccount::Asset
|| acc.accountGroup() == MyMoneyAccount::Liability) {
val = (*it_s).value();
accountCount++;
if(acc.accountType() == MyMoneyAccount::Loan
|| acc.accountType() == MyMoneyAccount::AssetLoan)
isLoan = true;
} else
break;
}
if(accountCount == 2) {
if(isLoan)
defaultAction = MyMoneySplit::ActionAmortization;
else
defaultAction = MyMoneySplit::ActionTransfer;
} else {
if(val.isNegative())
defaultAction = MyMoneySplit::ActionWithdrawal;
else
defaultAction = MyMoneySplit::ActionDeposit;
}
}
isLoan = false;
for(it_s = splits.begin(); defaultAction == 0 && it_s != splits.end(); ++it_s) {
MyMoneyAccount acc = file->account((*it_s).accountId());
MyMoneyMoney val = (*it_s).value();
if(acc.accountGroup() == MyMoneyAccount::Asset
|| acc.accountGroup() == MyMoneyAccount::Liability) {
if(!val.isPositive())
defaultAction = MyMoneySplit::ActionWithdrawal;
else
defaultAction = MyMoneySplit::ActionDeposit;
}
}
#if 0
// Check for correct actions in transactions referencing credit cards
bool needModify = false;
// The action fields are actually not used anymore in the ledger view logic
// so we might as well skip this whole thing here!
for(it_s = splits.begin(); needModify == false && it_s != splits.end(); ++it_s) {
MyMoneyAccount acc = file->account((*it_s).accountId());
MyMoneyMoney val = (*it_s).value();
if(acc.accountType() == MyMoneyAccount::CreditCard) {
if(val < 0 && (*it_s).action() != MyMoneySplit::ActionWithdrawal && (*it_s).action() != MyMoneySplit::ActionTransfer )
needModify = true;
if(val >= 0 && (*it_s).action() != MyMoneySplit::ActionDeposit && (*it_s).action() != MyMoneySplit::ActionTransfer)
needModify = true;
}
}
// (Ace) Extended the #endif down to cover this conditional, because as-written
// it will ALWAYS be skipped.
if(needModify == true) {
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
(*it_s).setAction(defaultAction);
(*it_t).modifySplit(*it_s);
file->modifyTransaction(*it_t);
}
splits = (*it_t).splits(); // update local copy
qDebug("Fixed credit card assignment in %s", (*it_t).id().data());
}
#endif
bool hasDuplicateAccounts = false;
// Check for correct assignment of ActionInterest in all splits
// and check if there are any duplicates in this transactions
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
MyMoneyAccount splitAccount = file->account((*it_s).accountId());
if(accounts.contains((*it_s).accountId())) {
hasDuplicateAccounts = true;
} else {
accounts << (*it_s).accountId();
}
// if this split references an interest account, the action
// must be of type ActionInterest
if(interestAccounts.contains((*it_s).accountId())) {
if((*it_s).action() != MyMoneySplit::ActionInterest) {
kdDebug(2) << __func__ << " " << (*it_t).id() << " contains an interest account (" << (*it_s).accountId() << ") but does not have ActionInterest" << endl;
(*it_s).setAction(MyMoneySplit::ActionInterest);
(*it_t).modifySplit(*it_s);
file->modifyTransaction(*it_t);
qDebug("Fixed interest action in %s", (*it_t).id().data());
}
// if it does not reference an interest account, it must not be
// of type ActionInterest
} else {
if((*it_s).action() == MyMoneySplit::ActionInterest) {
kdDebug(2) << __func__ << " " << (*it_t).id() << " does not contain an interest account so it should not have ActionInterest" << endl;
(*it_s).setAction(defaultAction);
(*it_t).modifySplit(*it_s);
file->modifyTransaction(*it_t);
qDebug("Fixed interest action in %s", (*it_t).id().data());
}
}
// check that for splits referencing an account that has
// the same currency as the transactions commodity the value
// and shares field are the same.
if((*it_t).commodity() == splitAccount.currencyId()
&& (*it_s).value() != (*it_s).shares()) {
kdDebug(2) << __func__ << " " << (*it_t).id() << " " << (*it_s).id() << " uses the transaction currency, but shares != value" << endl;
(*it_s).setShares((*it_s).value());
(*it_t).modifySplit(*it_s);
file->modifyTransaction(*it_t);
}
// fix the shares and values to have the correct fraction
if(!splitAccount.isInvest()) {
try {
int fract = splitAccount.fraction();
if((*it_s).shares() != (*it_s).shares().convert(fract)) {
qDebug("adjusting fraction in %s,%s", (*it_t).id().data(), (*it_s).id().data());
(*it_s).setShares((*it_s).shares().convert(fract));
(*it_s).setValue((*it_s).value().convert(fract));
(*it_t).modifySplit(*it_s);
file->modifyTransaction(*it_t);
}
} catch(MyMoneyException* e) {
qDebug("Missing security '%s', split not altered", splitAccount.currencyId().data());
delete e;
}
}
}
/*
// if there are at least two splits referencing the same account,
// we need to combine them into one and get rid of the others
if(hasDuplicateAccounts) {
fixDuplicateAccounts(*it_t);
}
*/
++cnt;
if(!(cnt % 10))
kmymoney2->slotStatusProgressBar(cnt);
}
kmymoney2->slotStatusProgressBar(-1, -1);
}
void KMyMoneyView::fixDuplicateAccounts_0(MyMoneyTransaction& t)
{
qDebug("Duplicate account in transaction %s", t.id().data());
}
void KMyMoneyView::slotPrintView(void)
{
if(pageIndex(m_reportsViewFrame) == activePageIndex())
m_reportsView->slotPrintView();
else if(pageIndex(m_homeViewFrame) == activePageIndex())
m_homeView->slotPrintView();
}
KMyMoneyViewBase* KMyMoneyView::addPage(const TQString& title, const TQString& icon)
{
const int iconSize = (KMyMoneyGlobalSettings::iconSize()+1)*16;
TQFrame* frm = KJanusWidget::addVBoxPage(title, title, DesktopIcon(icon, iconSize));
return new KMyMoneyViewBase(frm, title.latin1(), title);
}
/* ------------------------------------------------------------------------ */
/* KMyMoneyViewBase */
/* ------------------------------------------------------------------------ */
// ----------------------------------------------------------------------------
// QT Includes
#include
#include
// ----------------------------------------------------------------------------
// KDE Includes
// ----------------------------------------------------------------------------
// Project Includes
#include "../widgets/kmymoneytitlelabel.h"
class KMyMoneyViewBase::Private {
public:
TQFrame* m_titleLine;
KMyMoneyTitleLabel* m_titleLabel;
TQVBoxLayout* m_viewLayout;
};
KMyMoneyViewBase::KMyMoneyViewBase(TQWidget* tqparent, const char* name, const TQString& title) :
TQWidget(tqparent, name),
d(new Private)
{
d->m_viewLayout = new TQVBoxLayout(this);
d->m_viewLayout->setSpacing( 6 );
d->m_viewLayout->setMargin( 0 );
d->m_titleLabel = new KMyMoneyTitleLabel( this, "titleLabel" );
d->m_titleLabel->setMinimumSize( TQSize( 100, 30 ) );
d->m_titleLabel->setRightImageFile("pics/titlelabel_background.png" );
d->m_titleLabel->setText(title);
d->m_viewLayout->addWidget( d->m_titleLabel );
#if 0
d->m_titleLine = new TQFrame( this, "titleLine" );
d->m_titleLine->setFrameShape( TQFrame::HLine );
d->m_titleLine->setFrameShadow( TQFrame::Sunken );
d->m_titleLine->setFrameShape( TQFrame::HLine );
d->m_viewLayout->addWidget( d->m_titleLine );
#endif
}
KMyMoneyViewBase::~KMyMoneyViewBase()
{
delete d;
}
void KMyMoneyViewBase::addWidget(TQWidget* w)
{
d->m_viewLayout->addWidget(w);
}
TQVBoxLayout* KMyMoneyViewBase::tqlayout(void) const
{
return d->m_viewLayout;
}
#include "kmymoneyview.moc"