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/dialogs/kcurrencycalculator.cpp

320 lines
11 KiB

/***************************************************************************
kcurrencycalculator.cpp - description
-------------------
begin : Thu Apr 8 2004
copyright : (C) 2000-2004 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales <javi_c@users.sourceforge.net>
Felix Rodriguez <frodriguez@users.sourceforge.net>
John C <thetacoturtle@users.sourceforge.net>
Thomas Baumgart <ipwizard@users.sourceforge.net>
Kevin Tambascio <ktambascio@users.sourceforge.net>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// ----------------------------------------------------------------------------
// QT Includes
#include <tqlabel.h>
#include <tqradiobutton.h>
#include <tqcheckbox.h>
#include <tqwidgetstack.h>
#include <tqgroupbox.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <tdelocale.h>
#include <kpushbutton.h>
#include <kcombobox.h>
#include <kstdguiitem.h>
// ----------------------------------------------------------------------------
// Project Includes
#include "kcurrencycalculator.h"
#include <kmymoney/kmymoneyedit.h>
#include <kmymoney/kmymoneydateinput.h>
#include <kmymoney/kmymoneycurrencyselector.h>
#include <kmymoney/mymoneyprice.h>
#include <kmymoney/mymoneytransaction.h>
#include <kmymoney/kmymoneyglobalsettings.h>
#include "../kmymoneyutils.h"
bool KCurrencyCalculator::setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const TQMap<TQString, MyMoneyMoney>& priceInfo, TQWidget* parentWidget)
{
bool rc = true;
MyMoneyFile* file = MyMoneyFile::instance();
if(!s.value().isZero()) {
MyMoneyAccount cat = file->account(s.accountId());
MyMoneySecurity toCurrency;
toCurrency = file->security(cat.currencyId());
// determine the fraction required for this category/account
int fract = cat.fraction(toCurrency);
if(cat.currencyId() != t.commodity()) {
MyMoneySecurity fromCurrency;
MyMoneyMoney fromValue, toValue;
fromCurrency = file->security(t.commodity());
// display only positive values to the user
fromValue = s.value().abs();
// if we had a price info in the beginning, we use it here
if(priceInfo.find(cat.currencyId()) != priceInfo.end()) {
toValue = (fromValue * priceInfo[cat.currencyId()]).convert(fract);
}
// if the shares are still 0, we need to change that
if(toValue.isZero()) {
MyMoneyPrice price = file->price(fromCurrency.id(), toCurrency.id());
// if the price is valid calculate the shares. If it is invalid
// assume a conversion rate of 1.0
if(price.isValid()) {
toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract);
} else {
toValue = fromValue;
}
}
// now present all that to the user
KCurrencyCalculator calc(fromCurrency,
toCurrency,
fromValue,
toValue,
t.postDate(),
fract,
parentWidget, "currencyCalculator");
if(calc.exec() == TQDialog::Rejected) {
rc = false;
} else
shares = (s.value() * calc.price()).convert(fract);
} else {
shares = s.value().convert(fract);
}
} else
shares = s.value();
return rc;
}
KCurrencyCalculator::KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const TQDate& date, const signed64 resultFraction, TQWidget *parent, const char *name ) :
KCurrencyCalculatorDecl(parent, name),
m_fromCurrency(from),
m_toCurrency(to),
m_result(shares.abs()),
m_value(value.abs()),
m_resultFraction(resultFraction)
{
MyMoneyFile* file = MyMoneyFile::instance();
m_dateFrame->hide();
if(date.isValid())
m_dateEdit->setDate(date);
else
m_dateEdit->setDate(TQDate::currentDate());
m_fromCurrencyText->setText(m_fromCurrency.isCurrency() ? m_fromCurrency.id() : m_fromCurrency.tradingSymbol());
m_toCurrencyText->setText(m_toCurrency.isCurrency() ? m_toCurrency.id() : m_toCurrency.tradingSymbol());
m_fromAmount->setText(m_value.formatMoney("", MyMoneyMoney::denomToPrec(m_fromCurrency.smallestAccountFraction())));
m_dateText->setText(TDEGlobal::locale()->formatDate(date, true));
m_fromType->setText(KMyMoneyUtils::securityTypeToString(m_fromCurrency.securityType()));
m_toType->setText(KMyMoneyUtils::securityTypeToString(m_toCurrency.securityType()));
// load button icons
m_cancelButton->setGuiItem(KStdGuiItem::cancel());
m_okButton->setGuiItem(KStdGuiItem::ok());
m_updateButton->setChecked(KMyMoneyGlobalSettings::priceHistoryUpdate());
// setup initial result
if(m_result == MyMoneyMoney() && !m_value.isZero()) {
MyMoneyPrice pr = file->price(m_fromCurrency.id(), m_toCurrency.id(), date);
if(pr.isValid()) {
m_result = m_value * pr.rate(m_fromCurrency.id());
}
}
// fill in initial values
m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
m_toAmount->setPrecision(MyMoneyMoney::denomToPrec(m_resultFraction));
m_conversionRate->setPrecision(KMyMoneyGlobalSettings::pricePrecision());
connect(m_amountButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSetToAmount()));
connect(m_rateButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSetExchangeRate()));
connect(m_toAmount, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateResult(const TQString&)));
connect(m_conversionRate, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateRate(const TQString&)));
connect(m_cancelButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(reject()));
connect(m_okButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept()));
// use this as the default
m_amountButton->animateClick();
slotUpdateResult(m_toAmount->text());
// If the from security is not a currency, we only allow entering a price
if(!m_fromCurrency.isCurrency()) {
m_rateButton->animateClick();
m_amountButton->hide();
m_toAmount->hide();
}
m_okButton->setFocus();
}
KCurrencyCalculator::~KCurrencyCalculator()
{
}
void KCurrencyCalculator::setupPriceEditor(void)
{
m_dateFrame->show();
m_amountDateFrame->hide();
m_updateButton->setChecked(true);
m_updateButton->hide();
}
void KCurrencyCalculator::slotSetToAmount(void)
{
m_rateButton->setChecked(false);
m_toAmount->setEnabled(true);
m_conversionRate->setEnabled(false);
}
void KCurrencyCalculator::slotSetExchangeRate(void)
{
m_amountButton->setChecked(false);
m_toAmount->setEnabled(false);
m_conversionRate->setEnabled(true);
}
void KCurrencyCalculator::slotUpdateResult(const TQString& /*txt*/)
{
MyMoneyMoney result = m_toAmount->value();
MyMoneyMoney price(0, 1);
if(result.isNegative()) {
m_toAmount->setValue(-result);
slotUpdateResult(TQString());
return;
}
if(!result.isZero()) {
price = result / m_value;
m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
m_result = (m_value * price).convert(m_resultFraction);
m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
}
updateExample(price);
}
void KCurrencyCalculator::slotUpdateRate(const TQString& /*txt*/)
{
MyMoneyMoney price = m_conversionRate->value();
if(price.isNegative()) {
m_conversionRate->setValue(-price);
slotUpdateRate(TQString());
return;
}
if(!price.isZero()) {
m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
m_result = (m_value * price).convert(m_resultFraction);
m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
}
updateExample(price);
}
void KCurrencyCalculator::updateExample(const MyMoneyMoney& price)
{
TQString msg;
if(price.isZero()) {
msg = TQString("1 %1 = ? %2").arg(m_fromCurrency.tradingSymbol())
.arg(m_toCurrency.tradingSymbol());
if(m_fromCurrency.isCurrency()) {
msg += TQString("\n");
msg += TQString("1 %1 = ? %2").arg(m_toCurrency.tradingSymbol())
.arg(m_fromCurrency.tradingSymbol());
}
} else {
msg = TQString("1 %1 = %2 %3").arg(m_fromCurrency.tradingSymbol())
.arg(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
.arg(m_toCurrency.tradingSymbol());
if(m_fromCurrency.isCurrency()) {
msg += TQString("\n");
msg += TQString("1 %1 = %2 %3").arg(m_toCurrency.tradingSymbol())
.arg((MyMoneyMoney(1,1)/price).formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
.arg(m_fromCurrency.tradingSymbol());
}
}
m_conversionExample->setText(msg);
m_okButton->setEnabled(!price.isZero());
}
void KCurrencyCalculator::accept(void)
{
if(m_conversionRate->isEnabled())
slotUpdateRate(TQString());
else
slotUpdateResult(TQString());
if(m_updateButton->isChecked()) {
MyMoneyPrice pr = MyMoneyFile::instance()->price(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date());
if(!pr.isValid()
|| pr.date() != m_dateEdit->date()
|| (pr.date() == m_dateEdit->date() && pr.rate(m_fromCurrency.id()) != price())) {
pr = MyMoneyPrice(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date(), price(), i18n("User"));
MyMoneyFileTransaction ft;
try {
MyMoneyFile::instance()->addPrice(pr);
ft.commit();
} catch(MyMoneyException *e) {
tqDebug("Cannot add price");
delete e;
}
}
}
// remember setting for next round
KMyMoneyGlobalSettings::setPriceHistoryUpdate(m_updateButton->isChecked());
KCurrencyCalculatorDecl::accept();
}
const MyMoneyMoney KCurrencyCalculator::price(void) const
{
// This should fix https://bugs.kde.org/show_bug.cgi?id=205254 but
// I am not sure about any side effects when dealing with multi-
// currency transactions.
//
// The following line is the original version of this code
// which causes some rounding issues (see the above bug entry)
// return m_result / m_value;
return m_conversionRate->value();
}
#include "kcurrencycalculator.moc"