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/widgets/kmymoneycalculator.cpp

449 lines
12 KiB

/***************************************************************************
kmymoneycalculator.cpp - description
-------------------
begin : Sat Oct 19 2002
copyright : (C) 2000-2002 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. *
* *
***************************************************************************/
// ----------------------------------------------------------------------------
// QT Includes
#include <tqlabel.h>
#include <tqsignalmapper.h>
#include <tqregexp.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <kglobal.h>
#include <klocale.h>
// ----------------------------------------------------------------------------
// Project Includes
#include "kmymoneycalculator.h"
kMyMoneyCalculator::kMyMoneyCalculator(TQWidget* parent, const char *name)
: TQFrame(parent, name)
{
m_comma = KGlobal::locale()->monetaryDecimalSymbol()[0];
m_clearOperandOnDigit = false;
TQGridLayout* grid = new TQGridLayout(this, 5, 5, 1, 2);
display = new TQLabel(this);
display->setBackgroundColor(TQColor("#BDFFB4"));
display->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
display->setAlignment(TQt::AlignRight | TQt::AlignVCenter);
grid->addMultiCellWidget(display, 0, 0, 0, 4);
buttons[0] = new KPushButton("0", this);
buttons[1] = new KPushButton("1", this);
buttons[2] = new KPushButton("2", this);
buttons[3] = new KPushButton("3", this);
buttons[4] = new KPushButton("4", this);
buttons[5] = new KPushButton("5", this);
buttons[6] = new KPushButton("6", this);
buttons[7] = new KPushButton("7", this);
buttons[8] = new KPushButton("8", this);
buttons[9] = new KPushButton("9", this);
buttons[PLUS] = new KPushButton("+", this);
buttons[MINUS] = new KPushButton("-", this);
buttons[STAR] = new KPushButton("X", this);
buttons[COMMA] = new KPushButton(m_comma, this);
buttons[ETQUAL] = new KPushButton("=", this);
buttons[SLASH] = new KPushButton("/", this);
buttons[CLEAR] = new KPushButton("C", this);
buttons[CLEARALL] = new KPushButton("AC", this);
buttons[PLUSMINUS] = new KPushButton("+-", this);
buttons[PERCENT] = new KPushButton("%", this);
grid->addWidget(buttons[7], 1, 0);
grid->addWidget(buttons[8], 1, 1);
grid->addWidget(buttons[9], 1, 2);
grid->addWidget(buttons[4], 2, 0);
grid->addWidget(buttons[5], 2, 1);
grid->addWidget(buttons[6], 2, 2);
grid->addWidget(buttons[1], 3, 0);
grid->addWidget(buttons[2], 3, 1);
grid->addWidget(buttons[3], 3, 2);
grid->addWidget(buttons[0], 4, 1);
grid->addWidget(buttons[COMMA], 4, 0);
grid->addWidget(buttons[PLUS], 3, 3);
grid->addWidget(buttons[MINUS], 4, 3);
grid->addWidget(buttons[STAR], 3, 4);
grid->addWidget(buttons[SLASH], 4, 4);
grid->addWidget(buttons[ETQUAL], 4, 2);
grid->addWidget(buttons[PLUSMINUS], 2, 3);
grid->addWidget(buttons[PERCENT], 2, 4);
grid->addWidget(buttons[CLEAR], 1, 3);
grid->addWidget(buttons[CLEARALL], 1, 4);
buttons[ETQUAL]->setFocus();
op1 = 0.0;
stackedOp = op = 0;
operand = TQString();
changeDisplay("0");
// connect the digit signals through a signal mapper
TQSignalMapper* mapper = new TQSignalMapper(TQT_TQOBJECT(this));
for(int i = 0; i < 10; ++i) {
mapper->setMapping(TQT_TQOBJECT(buttons[i]), i);
connect(buttons[i], TQT_SIGNAL(clicked()), mapper, TQT_SLOT(map()));
}
connect(mapper, TQT_SIGNAL(mapped(int)), this, TQT_SLOT(digitClicked(int)));
// connect the calculation operations through another mapper
mapper = new TQSignalMapper(TQT_TQOBJECT(this));
for(int i = PLUS; i <= ETQUAL; ++i) {
mapper->setMapping(TQT_TQOBJECT(buttons[i]), i);
connect(buttons[i], TQT_SIGNAL(clicked()), mapper, TQT_SLOT(map()));
}
connect(mapper, TQT_SIGNAL(mapped(int)), this, TQT_SLOT(calculationClicked(int)));
// connect all remaining signals
connect(buttons[COMMA], TQT_SIGNAL(clicked()), TQT_SLOT(commaClicked()));
connect(buttons[PLUSMINUS], TQT_SIGNAL(clicked()), TQT_SLOT(plusminusClicked()));
connect(buttons[PERCENT], TQT_SIGNAL(clicked()), TQT_SLOT(percentClicked()));
connect(buttons[CLEAR], TQT_SIGNAL(clicked()), TQT_SLOT(clearClicked()));
connect(buttons[CLEARALL], TQT_SIGNAL(clicked()), TQT_SLOT(clearAllClicked()));
for(int i = 0; i < MAX_BUTTONS; ++i) {
buttons[i]->setMinimumSize(40, 30);
buttons[i]->setMaximumSize(40, 30);
}
int height = 4 * (buttons[0]->minimumHeight()+6) + 15;
int width = 5 * (buttons[0]->minimumWidth()+6);
setMinimumSize(width, height);
setMaximumSize(width, height);
show();
}
kMyMoneyCalculator::~kMyMoneyCalculator()
{
}
void kMyMoneyCalculator::digitClicked(int button)
{
if(m_clearOperandOnDigit) {
operand = TQString();
m_clearOperandOnDigit = false;
}
operand += TQChar(button + 0x30);
if(operand.length() > 16)
operand = operand.left(16);
changeDisplay(operand);
}
void kMyMoneyCalculator::commaClicked(void)
{
if(operand.length() == 0)
operand = "0";
if(operand.contains('.', FALSE) == 0)
operand.append('.');
if(operand.length() > 16)
operand = operand.left(16);
changeDisplay(operand);
}
void kMyMoneyCalculator::plusminusClicked(void)
{
if(operand.length() == 0 && m_result.length() > 0)
operand = m_result;
if(operand.length() > 0) {
if(operand.find('-') != -1)
operand.replace('-', TQString());
else
operand.prepend('-');
changeDisplay(operand);
}
}
void kMyMoneyCalculator::calculationClicked(int button)
{
if(operand.length() == 0 && op != 0 && button == ETQUAL) {
op = 0;
m_result = normalizeString(op1);
changeDisplay(m_result);
} else if(operand.length() > 0 && op != 0) {
// perform operation
double op2 = operand.toDouble();
bool error = false;
// if the pending operation is addition and we now do multiplication
// we just stack op1 and remember the operation in
if((op == PLUS || op == MINUS) && (button == STAR || button == SLASH)) {
op0 = op1;
stackedOp = op;
op = 0;
}
switch(op) {
case PLUS:
op2 = op1 + op2;
break;
case MINUS:
op2 = op1 - op2;
break;
case STAR:
op2 = op1 * op2;
break;
case SLASH:
if(op2 == 0.0)
error = true;
else
op2 = op1 / op2;
break;
}
// if we have a pending addition operation, and the next operation is
// not multiplication, we calculate the stacked operation
if(stackedOp && button != STAR && button != SLASH) {
switch(stackedOp) {
case PLUS:
op2 = op0 + op2;
break;
case MINUS:
op2 = op0 - op2;
break;
}
stackedOp = 0;
}
if(error) {
op = 0;
changeDisplay("Error");
operand = TQString();
} else {
op1 = op2;
m_result = normalizeString(op1);
changeDisplay(m_result);
}
} else if(operand.length() > 0 && op == 0) {
op1 = operand.toDouble();
m_result = normalizeString(op1);
changeDisplay(m_result);
}
if(button != ETQUAL) {
op = button;
} else {
op = 0;
emit signalResultAvailable();
}
operand = TQString();
}
TQString kMyMoneyCalculator::normalizeString(const double& val)
{
TQString str;
str.setNum(val, 'f');
int i = str.length();
while(i > 1 && str[i-1] == '0') {
--i;
}
// cut off trailing 0's
str.remove(i, str.length());
if(str.length() > 0) {
// possibly remove trailing period
if(str[str.length()-1] == '.') {
str.remove(str.length()-1, 1);
}
}
return str;
}
void kMyMoneyCalculator::clearClicked(void)
{
if(operand.length() > 0) {
operand = operand.left(operand.length() - 1);
}
if(operand.length() == 0)
changeDisplay("0");
else
changeDisplay(operand);
}
void kMyMoneyCalculator::clearAllClicked(void)
{
operand = TQString();
op = 0;
changeDisplay("0");
}
void kMyMoneyCalculator::percentClicked(void)
{
if(op != 0) {
double op2 = operand.toDouble();
switch(op) {
case PLUS:
case MINUS:
op2 = (op1 * op2) / 100;
break;
case STAR:
case SLASH:
op2 /= 100;
break;
}
operand = normalizeString(op2);
changeDisplay(operand);
}
}
const TQString kMyMoneyCalculator::result(void) const
{
TQString txt = m_result;
txt.replace(TQRegExp("\\."), m_comma);
if(txt[0] == '-') {
txt = txt.mid(1); // get rid of the minus sign
TQString mask;
switch(KGlobal::locale()->negativeMonetarySignPosition()) {
case KLocale::ParensAround:
mask = "(%1)";
break;
case KLocale::AfterQuantityMoney:
mask = "%1-";
break;
case KLocale::AfterMoney:
case KLocale::BeforeMoney:
mask = "%1 -";
break;
case KLocale::BeforeQuantityMoney:
mask = "-%1";
break;
}
txt = TQString(mask).tqarg(txt);
}
return txt;
}
void kMyMoneyCalculator::changeDisplay(const TQString& str)
{
TQString txt = str;
txt.replace(TQRegExp("\\."), m_comma);
display->setText("<b>" + txt + "</b>");
}
void kMyMoneyCalculator::keyPressEvent(TQKeyEvent* ev)
{
int button = -1;
switch(ev->key()) {
case TQt::Key_0:
case TQt::Key_1:
case TQt::Key_2:
case TQt::Key_3:
case TQt::Key_4:
case TQt::Key_5:
case TQt::Key_6:
case TQt::Key_7:
case TQt::Key_8:
case TQt::Key_9:
if(m_clearOperandOnDigit) {
operand = TQString();
m_clearOperandOnDigit = false;
}
button = ev->key() - TQt::Key_0;
break;
case TQt::Key_Plus:
button = PLUS;
break;
case TQt::Key_Minus:
button = MINUS;
break;
case TQt::Key_Comma:
case TQt::Key_Period:
if(m_clearOperandOnDigit) {
operand = TQString();
m_clearOperandOnDigit = false;
}
button = COMMA;
break;
case TQt::Key_Slash:
button = SLASH;
break;
case TQt::Key_Backspace:
button = CLEAR;
break;
case TQt::Key_Asterisk:
button = STAR;
break;
case TQt::Key_Return:
case TQt::Key_Enter:
case TQt::Key_Equal:
button = ETQUAL;
break;
case TQt::Key_Escape:
button = CLEARALL;
break;
case TQt::Key_Percent:
button = PERCENT;
break;
default:
ev->ignore();
break;
}
if(button != -1)
buttons[button]->animateClick();
m_clearOperandOnDigit = false;
}
void kMyMoneyCalculator::setInitialValues(const TQString& value, TQKeyEvent* ev)
{
bool negative = false;
// setup operand
operand = value;
operand.replace(TQRegExp(TQString("\\")+KGlobal::locale()->thousandsSeparator()), TQString());
operand.replace(TQRegExp(TQString("\\")+m_comma), ".");
if(operand.contains('(')) {
negative = true;
operand.replace("(", TQString());
operand.replace(")", TQString());
}
if(operand.contains('-')) {
negative = true;
operand.replace("-", TQString());
}
if(operand.isEmpty())
operand = "0";
else if(negative)
operand = TQString("-%1").tqarg(operand);
changeDisplay(operand);
// and operation
op = 0;
if(ev)
keyPressEvent(ev);
else
m_clearOperandOnDigit = true;
}
#include "kmymoneycalculator.moc"