summaryrefslogtreecommitdiffstats
path: root/kmymoney2/widgets/kmymoneycalculator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmymoney2/widgets/kmymoneycalculator.cpp')
-rw-r--r--kmymoney2/widgets/kmymoneycalculator.cpp448
1 files changed, 448 insertions, 0 deletions
diff --git a/kmymoney2/widgets/kmymoneycalculator.cpp b/kmymoney2/widgets/kmymoneycalculator.cpp
new file mode 100644
index 0000000..3e59331
--- /dev/null
+++ b/kmymoney2/widgets/kmymoneycalculator.cpp
@@ -0,0 +1,448 @@
+/***************************************************************************
+ 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 <qlabel.h>
+#include <qsignalmapper.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kglobal.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneycalculator.h"
+
+kMyMoneyCalculator::kMyMoneyCalculator(QWidget* parent, const char *name)
+ : QFrame(parent, name)
+{
+ m_comma = KGlobal::locale()->monetaryDecimalSymbol()[0];
+ m_clearOperandOnDigit = false;
+
+ QGridLayout* grid = new QGridLayout(this, 5, 5, 1, 2);
+
+ display = new QLabel(this);
+ display->setBackgroundColor(QColor("#BDFFB4"));
+
+ display->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ display->setAlignment(Qt::AlignRight | Qt::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[EQUAL] = 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[EQUAL], 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[EQUAL]->setFocus();
+
+ op1 = 0.0;
+ stackedOp = op = 0;
+ operand = QString();
+ changeDisplay("0");
+
+ // connect the digit signals through a signal mapper
+ QSignalMapper* mapper = new QSignalMapper(this);
+ for(int i = 0; i < 10; ++i) {
+ mapper->setMapping(buttons[i], i);
+ connect(buttons[i], SIGNAL(clicked()), mapper, SLOT(map()));
+ }
+ connect(mapper, SIGNAL(mapped(int)), this, SLOT(digitClicked(int)));
+
+ // connect the calculation operations through another mapper
+ mapper = new QSignalMapper(this);
+ for(int i = PLUS; i <= EQUAL; ++i) {
+ mapper->setMapping(buttons[i], i);
+ connect(buttons[i], SIGNAL(clicked()), mapper, SLOT(map()));
+ }
+ connect(mapper, SIGNAL(mapped(int)), this, SLOT(calculationClicked(int)));
+
+ // connect all remaining signals
+ connect(buttons[COMMA], SIGNAL(clicked()), SLOT(commaClicked()));
+ connect(buttons[PLUSMINUS], SIGNAL(clicked()), SLOT(plusminusClicked()));
+ connect(buttons[PERCENT], SIGNAL(clicked()), SLOT(percentClicked()));
+ connect(buttons[CLEAR], SIGNAL(clicked()), SLOT(clearClicked()));
+ connect(buttons[CLEARALL], SIGNAL(clicked()), 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 = QString();
+ m_clearOperandOnDigit = false;
+ }
+
+ operand += QChar(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('-', QString());
+ else
+ operand.prepend('-');
+ changeDisplay(operand);
+ }
+}
+
+void kMyMoneyCalculator::calculationClicked(int button)
+{
+ if(operand.length() == 0 && op != 0 && button == EQUAL) {
+ 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 = QString();
+ } 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 != EQUAL) {
+ op = button;
+ } else {
+ op = 0;
+ emit signalResultAvailable();
+ }
+ operand = QString();
+}
+
+QString kMyMoneyCalculator::normalizeString(const double& val)
+{
+ QString 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 = QString();
+ 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 QString kMyMoneyCalculator::result(void) const
+{
+ QString txt = m_result;
+ txt.replace(QRegExp("\\."), m_comma);
+ if(txt[0] == '-') {
+ txt = txt.mid(1); // get rid of the minus sign
+ QString 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 = QString(mask).arg(txt);
+ }
+ return txt;
+}
+
+void kMyMoneyCalculator::changeDisplay(const QString& str)
+{
+ QString txt = str;
+ txt.replace(QRegExp("\\."), m_comma);
+ display->setText("<b>" + txt + "</b>");
+}
+
+void kMyMoneyCalculator::keyPressEvent(QKeyEvent* ev)
+{
+ int button = -1;
+
+ switch(ev->key()) {
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ if(m_clearOperandOnDigit) {
+ operand = QString();
+ m_clearOperandOnDigit = false;
+ }
+ button = ev->key() - Qt::Key_0;
+ break;
+ case Qt::Key_Plus:
+ button = PLUS;
+ break;
+ case Qt::Key_Minus:
+ button = MINUS;
+ break;
+ case Qt::Key_Comma:
+ case Qt::Key_Period:
+ if(m_clearOperandOnDigit) {
+ operand = QString();
+ m_clearOperandOnDigit = false;
+ }
+ button = COMMA;
+ break;
+ case Qt::Key_Slash:
+ button = SLASH;
+ break;
+ case Qt::Key_Backspace:
+ button = CLEAR;
+ break;
+ case Qt::Key_Asterisk:
+ button = STAR;
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Equal:
+ button = EQUAL;
+ break;
+ case Qt::Key_Escape:
+ button = CLEARALL;
+ break;
+ case Qt::Key_Percent:
+ button = PERCENT;
+ break;
+ default:
+ ev->ignore();
+ break;
+ }
+ if(button != -1)
+ buttons[button]->animateClick();
+
+ m_clearOperandOnDigit = false;
+}
+
+void kMyMoneyCalculator::setInitialValues(const QString& value, QKeyEvent* ev)
+{
+ bool negative = false;
+ // setup operand
+ operand = value;
+ operand.replace(QRegExp(QString("\\")+KGlobal::locale()->thousandsSeparator()), QString());
+ operand.replace(QRegExp(QString("\\")+m_comma), ".");
+ if(operand.contains('(')) {
+ negative = true;
+ operand.replace("(", QString());
+ operand.replace(")", QString());
+ }
+ if(operand.contains('-')) {
+ negative = true;
+ operand.replace("-", QString());
+ }
+ if(operand.isEmpty())
+ operand = "0";
+ else if(negative)
+ operand = QString("-%1").arg(operand);
+
+ changeDisplay(operand);
+
+ // and operation
+ op = 0;
+ if(ev)
+ keyPressEvent(ev);
+ else
+ m_clearOperandOnDigit = true;
+}
+
+#include "kmymoneycalculator.moc"