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