|
|
|
/***************************************************************************
|
|
|
|
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"
|