File indexing completed on 2024-04-21 13:24:46

0001 /***************************************************************************
0002                           keurocalc.cpp  -  main widget
0003                              -------------------
0004     begin                : sam déc  1 23:40:19 CET 2001
0005     copyright            : (C) 2001-2022 by Éric Bischoff
0006     email                : bischoff@kde.org
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include <stdlib.h>
0019 #include <math.h>
0020 #include <locale.h>
0021 
0022 #include <QDBusConnection>
0023 #include <QPushButton>
0024 #include <QKeyEvent>
0025 
0026 #include <KLocalizedString>
0027 #include <KConfigGroup>
0028 #include <KSharedConfig>
0029 #include <KAboutData>
0030 #include <KAboutApplicationDialog>
0031 #include <KMessageBox>
0032 #include <KHelpClient>
0033 
0034 #include "keurocalc.h"
0035 #include "preferences.h"
0036 
0037 #include <config-keurocalc.h>
0038 
0039 #if HAVE_XLOCALE_H
0040 #include <xlocale.h>
0041 #endif
0042 
0043 static const char
0044     *euroSymbol = " €";
0045 //  *dollarSymbol = " $";
0046 
0047 // Constructor
0048 KEuroCalc::KEuroCalc(QWidget *parent)
0049     : QDialog(parent), Ui::Calculator(),
0050           currencies()
0051 {
0052     int position;
0053     QPalette palette;
0054 
0055     setupUi(this);
0056     QDBusConnection::sessionBus().registerObject
0057         ("/KEuroCalc", this, QDBusConnection::ExportScriptableSlots);
0058     connect( &currencies, SIGNAL(endDownload(int,QString)),
0059              this, SLOT(endDownload(int,QString))
0060            );
0061 
0062     c_locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
0063     isSimpleValue = false;
0064     simpleValue = 0.0;
0065     referenceValue = 0.0;
0066     currencyValue = 0.0;
0067 
0068     memorySet = false;
0069     isSimpleMemory = false;
0070     simpleMemory = 0.0;
0071     referenceMemory = 0.0;
0072 
0073     if ( !currencies.readCurrencies( "currencies.xml" ) )
0074     {
0075         KMessageBox::error( 0, i18n( "Cannot load currencies.xml" ) );
0076         exit(1);
0077     }
0078     readOptions( reference, currencyNum, rounding, displayColor, splashScreen );
0079 
0080     displayNewCurrency();
0081     displayNewResult();
0082     resetInput();
0083     initButtons();
0084     startDownload();
0085 
0086     position = currencies.position(currencyNum);
0087     if (position < 0) position = 0;
0088     CurrencyList->setCurrentIndex( position );
0089 
0090     palette.setColor( backgroundRole(), displayColor );
0091     ResultDisplay->setPalette( palette );
0092     InputDisplay->setPalette( palette );
0093     OperatorDisplay->setPalette( palette );
0094 
0095     setFocusPolicy( Qt::StrongFocus );
0096     connect(ZeroButton, &QAbstractButton::pressed, this, &KEuroCalc::InputZero);
0097     connect(FiveButton, &QAbstractButton::pressed, this, &KEuroCalc::InputFive);
0098     connect(FourButton, &QAbstractButton::pressed, this, &KEuroCalc::InputFour);
0099     connect(SevenButton, &QAbstractButton::pressed, this, &KEuroCalc::InputSeven);
0100     connect(SixButton, &QAbstractButton::pressed, this, &KEuroCalc::InputSix);
0101     connect(ThreeButton, &QAbstractButton::pressed, this, &KEuroCalc::InputThree);
0102     connect(TwoButton, &QAbstractButton::pressed, this, &KEuroCalc::InputTwo);
0103     connect(EightButton, &QAbstractButton::pressed, this, &KEuroCalc::InputEight);
0104     connect(NineButton, &QAbstractButton::pressed, this, &KEuroCalc::InputNine);
0105     connect(HelpButton, &QAbstractButton::pressed, this, &KEuroCalc::DisplayHelp);
0106     connect(DotButton, &QAbstractButton::pressed, this, &KEuroCalc::InputDot);
0107     connect(OneButton, &QAbstractButton::pressed, this, &KEuroCalc::InputOne);
0108     connect(BackspaceButton, &QAbstractButton::pressed, this, &KEuroCalc::InputBackspace);
0109     connect(ResetButton, &QAbstractButton::pressed, this, &KEuroCalc::Reset);
0110     connect(ReferenceButton, &QAbstractButton::pressed, this, &KEuroCalc::ValidateReference);
0111     connect(SlashButton, &QAbstractButton::pressed, this, &KEuroCalc::InputSlash);
0112     connect(AsteriskButton, &QAbstractButton::pressed, this, &KEuroCalc::InputAsterisk);
0113     connect(MinusButton, &QAbstractButton::pressed, this, &KEuroCalc::InputMinus);
0114     connect(PlusButton, &QAbstractButton::pressed, this, &KEuroCalc::InputPlus);
0115     connect(CurrencyButton, &QAbstractButton::pressed, this, &KEuroCalc::ValidateCurrency);
0116     connect(PercentButton, &QAbstractButton::pressed, this, &KEuroCalc::ValidatePercent);
0117     connect(PlusMinusButton, &QAbstractButton::pressed, this, &KEuroCalc::ChangeSign);
0118     connect(SimpleValueButton, &QAbstractButton::pressed, this, &KEuroCalc::ValidateSimpleValue);
0119     connect(AboutButton, &QAbstractButton::pressed, this, &KEuroCalc::DisplayAbout);
0120     connect(MInputButton, &QAbstractButton::pressed, this, &KEuroCalc::MemoryInput);
0121     connect(MRecallButton, &QAbstractButton::pressed, this, &KEuroCalc::MemoryRecall);
0122     connect(MMinusButton, &QAbstractButton::pressed, this, &KEuroCalc::MemoryMinus);
0123     connect(MPlusButton, &QAbstractButton::pressed, this, &KEuroCalc::MemoryPlus);
0124     connect(CurrencyList, &QComboBox::activated, this, &KEuroCalc::SelectCurrency);
0125     connect(SettingsButton, &QAbstractButton::pressed, this, &KEuroCalc::DisplaySettings);
0126 }
0127 
0128 // Destructor
0129 KEuroCalc::~KEuroCalc()
0130 {
0131     freelocale(c_locale);
0132 }
0133 
0134 // Is splash screen to be displayed ?
0135 bool KEuroCalc::readSplashScreen() const
0136 {
0137     KConfigGroup config(KSharedConfig::openConfig(), "General");
0138     QString option;
0139 
0140     option = config.readEntry("SplashScreen", "yes");
0141 
0142     return option == "yes";
0143 }
0144 
0145 // Read options from preferences file
0146 void KEuroCalc::readOptions(int &oldReference, int &oldCurrency, int &oldRounding, QColor &oldDisplayColor, bool &oldSplashScreen) const
0147 {
0148     KConfigGroup config(KSharedConfig::openConfig(), "General");
0149     QString option;
0150 
0151     option = config.readEntry("Reference", "EURO_ECB");
0152     if (option == "EURO_FIXED")
0153         oldReference = EURO_FIXED;
0154     else if (option == "EURO_ECB")
0155         oldReference = EURO_ECB;
0156 //  else if (option == "DOLLAR_NY_FRB")
0157 //      oldReference = DOLLAR_NY_FRB;
0158     else if (option == "EURO_TG")
0159         oldReference = EURO_TG;
0160     else oldReference = EURO_ECB;
0161 
0162     option = config.readEntry("Currency", "USD");
0163     for (oldCurrency = 0; oldCurrency < currencies.number(); ++oldCurrency)
0164         if ( option == currencies.code(oldCurrency) )
0165             break;
0166     if ( oldCurrency == currencies.number() )
0167         oldCurrency = currencies.dollar();
0168 
0169     option = config.readEntry("Rounding", "OFFICIAL_RULES");
0170     if (option == "OFFICIAL_RULES")
0171         oldRounding = OFFICIAL_RULES;
0172     else if (option == "SMALLEST_COIN")
0173         oldRounding = SMALLEST_COIN;
0174     else if (option == "NO_ROUNDING")
0175         oldRounding = NO_ROUNDING;
0176     else oldRounding = OFFICIAL_RULES;
0177 
0178     option = config.readEntry("DiplayColor", "#C0FFFF");
0179     oldDisplayColor.setNamedColor(option);
0180 
0181     option = config.readEntry("SplashScreen", "yes");
0182     oldSplashScreen = option == "yes";
0183 }
0184 
0185 // Write options to preferences file
0186 void KEuroCalc::writeOptions(int newReference, int newCurrency, int newRounding, const QColor &newDisplayColor, bool newSplashScreen)
0187 {
0188     KConfigGroup config(KSharedConfig::openConfig(), "General");
0189 
0190     switch (newReference)
0191     {   case EURO_FIXED:
0192             config.writeEntry("Reference", "EURO_FIXED");
0193             break;
0194         case EURO_ECB:
0195             config.writeEntry("Reference", "EURO_ECB");
0196             break;
0197 //      case DOLLAR_NY_FRB:
0198 //          config.writeEntry("Reference", "DOLLAR_NY_FRB");
0199 //          break;
0200         case EURO_TG:
0201             config.writeEntry("Reference", "EURO_TG");
0202     }
0203 
0204     config.writeEntry("Currency", currencies.code(newCurrency) );
0205 
0206     switch (newRounding)
0207     {   case OFFICIAL_RULES:
0208             config.writeEntry("Rounding", "OFFICIAL_RULES");
0209             break;
0210         case SMALLEST_COIN:
0211             config.writeEntry("Rounding", "SMALLEST_COIN");
0212             break;
0213         case NO_ROUNDING:
0214             config.writeEntry("Rounding", "NO_ROUNDING");
0215     }
0216 
0217     config.writeEntry("DiplayColor", newDisplayColor.name());
0218 
0219     config.writeEntry("SplashScreen", newSplashScreen? "yes": "no");
0220 
0221     config.sync();
0222 }
0223 
0224 // Set new preferences dialog
0225 void KEuroCalc::setPreferences(int newReference, int newCurrency, int newRounding, const QColor &newDisplayColor, bool newSplashScreen)
0226 {
0227     reference = newReference;
0228     currencyNum = newCurrency;
0229     rounding = newRounding;
0230     displayColor = newDisplayColor;
0231     splashScreen = newSplashScreen;
0232 
0233     CurrencyList->clear();
0234     initButtons();
0235     startDownload();
0236     Reset();
0237 }
0238 
0239 // Handle key press events
0240 void KEuroCalc::keyPressEvent(QKeyEvent *e)
0241 {
0242     switch (e->key())
0243     {
0244         case Qt::Key_Period:
0245         case Qt::Key_Comma:
0246             inputDigit('.');
0247             break;
0248         case Qt::Key_0:
0249             ZeroButton->animateClick();
0250             break;
0251         case Qt::Key_1:
0252             OneButton->animateClick();
0253             break;
0254         case Qt::Key_2:
0255             TwoButton->animateClick();
0256             break;
0257         case Qt::Key_3:
0258             ThreeButton->animateClick();
0259             break;
0260         case Qt::Key_4:
0261             FourButton->animateClick();
0262             break;
0263         case Qt::Key_5:
0264             FiveButton->animateClick();
0265             break;
0266         case Qt::Key_6:
0267             SixButton->animateClick();
0268             break;
0269         case Qt::Key_7:
0270             SevenButton->animateClick();
0271             break;
0272         case Qt::Key_8:
0273             EightButton->animateClick();
0274             break;
0275         case Qt::Key_9:
0276             NineButton->animateClick();
0277             break;
0278         case Qt::Key_Plus:
0279             PlusButton->animateClick();
0280             break;
0281         case Qt::Key_Minus:
0282             MinusButton->animateClick();
0283             break;
0284         case Qt::Key_Asterisk:
0285             AsteriskButton->animateClick();
0286             break;
0287         case Qt::Key_Slash:
0288             SlashButton->animateClick();
0289             break;
0290         case Qt::Key_Backspace:
0291             BackspaceButton->animateClick();
0292             break;
0293         case Qt::Key_E:
0294         case Qt::Key_Dollar:
0295             ReferenceButton->animateClick();
0296             break;
0297         case Qt::Key_Percent:
0298             PercentButton->animateClick();
0299             break;
0300         case Qt::Key_Enter:
0301         case Qt::Key_Return:
0302             SimpleValueButton->animateClick();
0303             break;
0304         case Qt::Key_S:
0305             PlusMinusButton->animateClick();
0306             break;
0307         case Qt::Key_Shift:
0308         case Qt::Key_Control:
0309         case Qt::Key_Meta:
0310         case Qt::Key_Alt:
0311         case Qt::Key_CapsLock:
0312         case Qt::Key_NumLock:
0313         case Qt::Key_ScrollLock:
0314             break;
0315         default:
0316             CurrencyButton->animateClick();
0317             break;
0318     }
0319 }
0320 
0321 // Dot button or key pressed
0322 void KEuroCalc::InputDot()
0323 {
0324     inputDigit('.');
0325 }
0326 
0327 // Zero button or key pressed
0328 void KEuroCalc::InputZero()
0329 {
0330     inputDigit('0');
0331 }
0332 
0333 // One button or key pressed
0334 void KEuroCalc::InputOne()
0335 {
0336     inputDigit('1');
0337 }
0338 
0339 // Two button or key pressed
0340 void KEuroCalc::InputTwo()
0341 {
0342     inputDigit('2');
0343 }
0344 
0345 // Three button or key pressed
0346 void KEuroCalc::InputThree()
0347 {
0348     inputDigit('3');
0349 }
0350 
0351 // Four button or key pressed
0352 void KEuroCalc::InputFour()
0353 {
0354     inputDigit('4');
0355 }
0356 
0357 // Five button or key pressed
0358 void KEuroCalc::InputFive()
0359 {
0360     inputDigit('5');
0361 }
0362 
0363 // Six button or key pressed
0364 void KEuroCalc::InputSix()
0365 {
0366     inputDigit('6');
0367 }
0368 
0369 // Seven button or key pressed
0370 void KEuroCalc::InputSeven()
0371 {
0372     inputDigit('7');
0373 }
0374 
0375 // Eight button or key pressed
0376 void KEuroCalc::InputEight()
0377 {
0378     inputDigit('8');
0379 }
0380 
0381 // Nine button or key pressed
0382 void KEuroCalc::InputNine()
0383 {
0384     inputDigit('9');
0385 }
0386 
0387 // Plus button or key pressed
0388 void KEuroCalc::InputPlus()
0389 {
0390     inputOperator('+');
0391 }
0392 
0393 // Minus button or key pressed
0394 void KEuroCalc::InputMinus()
0395 {
0396     inputOperator('-');
0397 }
0398 
0399 // Multiply button or key pressed
0400 void KEuroCalc::InputAsterisk()
0401 {
0402     inputOperator('x');
0403 }
0404 
0405 // Divide button or key pressed
0406 void KEuroCalc::InputSlash()
0407 {
0408     inputOperator('/');
0409 }
0410 
0411 // Correct last entered digit
0412 void KEuroCalc::InputBackspace()
0413 {
0414     inputCorrect();
0415 }
0416 
0417 // Convert to currency, and add or subtract too if needed
0418 void KEuroCalc::ValidateReference()
0419 {
0420     double inputValue, currencyRate, currencyPrecision;
0421 
0422     inputValue = strtod_l( inputDisplay, NULL, c_locale );
0423     currencyRate = currencies.rate(currencyNum);
0424     switch (rounding)
0425     {
0426         case OFFICIAL_RULES:
0427             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0428             break;
0429         case SMALLEST_COIN:
0430             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0431             break;
0432         default:
0433             currencyPrecision = 1.0;
0434     }
0435     if ( inputDisplay[10] == ' ' )
0436     {
0437         if ( isSimpleValue && *operatorDisplay == ' ' )
0438         {
0439             isSimpleValue = false;
0440             referenceValue = simpleValue;
0441             currencyValue = referenceValue * currencyRate * currencyPrecision;
0442             displayNewResult();
0443         }
0444         else QApplication::beep();
0445         return;
0446     }
0447 
0448     switch ( *operatorDisplay )
0449     {
0450         case ' ':
0451             isSimpleValue = false;
0452             referenceValue = inputValue;
0453             currencyValue = referenceValue * currencyRate * currencyPrecision;
0454             break;
0455         case '+':
0456             if ( isSimpleValue )
0457             {
0458                 QApplication::beep();
0459                 return;
0460             }
0461             referenceValue += inputValue;
0462             currencyValue = referenceValue * currencyRate * currencyPrecision;
0463             break;
0464         case '-':
0465             if ( isSimpleValue )
0466             {
0467                 QApplication::beep();
0468                 return;
0469             }
0470             referenceValue -= inputValue;
0471             currencyValue = referenceValue * currencyRate * currencyPrecision;
0472             break;
0473         case 'x':
0474             if ( isSimpleValue )
0475             {
0476                 isSimpleValue = false;
0477                 referenceValue = simpleValue * inputValue;
0478                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0479             }
0480             else
0481             {
0482                 QApplication::beep();
0483                 return;
0484             }
0485             break;
0486         case '/':
0487             if ( !isSimpleValue && inputValue != 0.0 )
0488             {
0489                 isSimpleValue = true;
0490                 simpleValue = referenceValue / inputValue;
0491             }
0492             else
0493             {
0494                 QApplication::beep();
0495                 return;
0496             }
0497     }
0498     resetInput();
0499     displayNewResult();
0500     displayMemoryButtons();
0501 }
0502 
0503 // Convert to reference, and add or subtract too if needed
0504 void KEuroCalc::ValidateCurrency()
0505 {
0506     double inputValue, currencyRate, currencyPrecision;
0507 
0508     inputValue = strtod_l( inputDisplay, NULL, c_locale );
0509     currencyRate = currencies.rate(currencyNum);
0510     switch (rounding)
0511     {
0512         case OFFICIAL_RULES:
0513             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0514             break;
0515         case SMALLEST_COIN:
0516             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0517             break;
0518         default:
0519             currencyPrecision = 1.0;
0520     }
0521 
0522     if ( inputDisplay[10] == ' ' )
0523     {
0524         if ( isSimpleValue && *operatorDisplay == ' ' )
0525         {
0526             isSimpleValue = false;
0527             currencyValue = simpleValue;
0528             referenceValue = currencyValue / currencyRate / currencyPrecision;
0529             displayNewResult();
0530         }
0531         else QApplication::beep();
0532         return;
0533     }
0534 
0535     switch ( *operatorDisplay )
0536     {
0537         case ' ':
0538             isSimpleValue = false;
0539             currencyValue = inputValue;
0540             referenceValue = currencyValue / currencyRate / currencyPrecision;
0541             break;
0542         case '+':
0543             if ( isSimpleValue )
0544             {
0545                 QApplication::beep();
0546                 return;
0547             }
0548             currencyValue += inputValue;
0549             referenceValue = currencyValue / currencyRate / currencyPrecision;
0550             break;
0551         case '-':
0552             if ( isSimpleValue )
0553             {
0554                 QApplication::beep();
0555                 return;
0556             }
0557             currencyValue -= inputValue;
0558             referenceValue = currencyValue / currencyRate / currencyPrecision;
0559             break;
0560         case 'x':
0561             if ( isSimpleValue )
0562             {
0563                 isSimpleValue = false;
0564                 currencyValue = simpleValue * inputValue;
0565                 referenceValue = currencyValue / currencyRate / currencyPrecision;
0566             }
0567             else
0568             {
0569                 QApplication::beep();
0570                 return;
0571             }
0572             break;
0573         case '/':
0574             if ( !isSimpleValue && inputValue != 0.0 )
0575             {
0576                 isSimpleValue = true;
0577                 simpleValue = currencyValue / inputValue;
0578             }
0579             else
0580             {
0581                 QApplication::beep();
0582                 return;
0583             }
0584     }
0585     resetInput();
0586     displayNewResult();
0587     displayMemoryButtons();
0588 }
0589 
0590 // Apply percentage, and add or subtract too if needed
0591 void KEuroCalc::ValidatePercent()
0592 {
0593     double inputValue, currencyRate, currencyPrecision;
0594 
0595     inputValue = strtod_l( inputDisplay, NULL, c_locale );
0596     currencyRate = currencies.rate(currencyNum);
0597     switch (rounding)
0598     {
0599         case OFFICIAL_RULES:
0600             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0601             break;
0602         case SMALLEST_COIN:
0603             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0604             break;
0605         default:
0606             currencyPrecision = 1.0;
0607     }
0608 
0609     if ( inputDisplay[10] == ' ' )
0610     {
0611         QApplication::beep();
0612         return;
0613     }
0614 
0615     switch ( *operatorDisplay )
0616     {
0617         case ' ':
0618             if ( isSimpleValue )
0619                 simpleValue = (inputValue * simpleValue) / 100.0;
0620             else
0621             {
0622                 referenceValue = (inputValue * referenceValue) / 100.0;
0623                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0624             }
0625             break;
0626         case '+':
0627             if ( isSimpleValue )
0628                 simpleValue = ((100.0 + inputValue) * simpleValue) / 100.0;
0629             else
0630             {
0631                 referenceValue = ((100.0 + inputValue) * referenceValue) / 100.0;
0632                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0633             }
0634             break;
0635         case '-':
0636             if ( isSimpleValue )
0637                 simpleValue = ((100.0 - inputValue) * simpleValue) / 100.0;
0638             else
0639             {
0640                 referenceValue = ((100.0 - inputValue) * referenceValue) / 100.0;
0641                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0642             }
0643             break;
0644         case 'x':
0645         case '/':
0646             QApplication::beep();
0647             return;
0648     }
0649     resetInput();
0650     displayNewResult();
0651 }
0652 
0653 // Enter a simple value, and multiply or divide too if needed.
0654 void KEuroCalc::ValidateSimpleValue()
0655 {
0656     double inputValue, currencyRate, currencyPrecision;
0657 
0658     inputValue = strtod_l( inputDisplay, NULL, c_locale );
0659     currencyRate = currencies.rate(currencyNum);
0660     switch (rounding)
0661     {
0662         case OFFICIAL_RULES:
0663             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0664             break;
0665         case SMALLEST_COIN:
0666             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0667             break;
0668         default:
0669             currencyPrecision = 1.0;
0670     }
0671 
0672     if ( inputDisplay[10] == ' ' )
0673     {
0674         QApplication::beep();
0675         return;
0676     }
0677 
0678     switch ( *operatorDisplay )
0679     {
0680         case ' ':
0681             isSimpleValue = true;
0682             simpleValue = inputValue;
0683             break;
0684         case '+':
0685             if ( isSimpleValue )
0686                 simpleValue += inputValue;
0687             else
0688             {
0689                 QApplication::beep();
0690                 return;
0691             }
0692             break;
0693         case '-':
0694             if ( isSimpleValue )
0695                 simpleValue -= inputValue;
0696             else
0697             {
0698                 QApplication::beep();
0699                 return;
0700             }
0701             break;
0702         case 'x':
0703             if ( isSimpleValue )
0704                 simpleValue *= inputValue;
0705             else
0706             {
0707                 referenceValue *= inputValue;
0708                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0709             }
0710             break;
0711         case '/':
0712             if ( inputValue == 0.0 )
0713             {
0714                 QApplication::beep();
0715                 return;
0716             }
0717             if ( isSimpleValue )
0718                 simpleValue /= inputValue;
0719             else
0720             {
0721                 referenceValue /= inputValue;
0722                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0723             }
0724             break;
0725         default:
0726             QApplication::beep();
0727             return;
0728     }
0729     resetInput();
0730     displayNewResult();
0731     displayMemoryButtons();
0732 }
0733 
0734 // Change the sign of the result
0735 void KEuroCalc::ChangeSign()
0736 {
0737     double currencyRate, currencyPrecision;
0738 
0739     currencyRate = currencies.rate(currencyNum);
0740     switch (rounding)
0741     {
0742         case OFFICIAL_RULES:
0743             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0744             break;
0745         case SMALLEST_COIN:
0746             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0747             break;
0748         default:
0749             currencyPrecision = 1.0;
0750     }
0751 
0752     if ( isSimpleValue )
0753         simpleValue = -simpleValue;
0754     else
0755     {
0756         referenceValue = -referenceValue;
0757         currencyValue = referenceValue * currencyRate * currencyPrecision;
0758     }
0759     displayNewResult();
0760 }
0761 
0762 // Transfer from display to memory
0763 void KEuroCalc::MemoryInput()
0764 {
0765     memorySet = true;
0766     isSimpleMemory = isSimpleValue;
0767     simpleMemory = simpleValue;
0768     referenceMemory = referenceValue;
0769 
0770     displayMemoryButtons();
0771 }
0772 
0773 // Transfer from memory to display
0774 void KEuroCalc::MemoryRecall()
0775 {
0776     double currencyRate, currencyPrecision;
0777 
0778     currencyRate = currencies.rate(currencyNum);
0779     switch (rounding)
0780     {
0781         case OFFICIAL_RULES:
0782             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0783             break;
0784         case SMALLEST_COIN:
0785             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0786             break;
0787         default:
0788             currencyPrecision = 1.0;
0789     }
0790 
0791     if ( !memorySet )
0792     {
0793         QApplication::beep();
0794         return;
0795     }
0796 
0797     switch ( *operatorDisplay )
0798     {
0799         case ' ':
0800             isSimpleValue = isSimpleMemory;
0801             if ( isSimpleMemory )
0802                 simpleValue = simpleMemory;
0803             else
0804             {
0805                 referenceValue = referenceMemory;
0806                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0807             }
0808             break;
0809         case '+':
0810             if ( isSimpleValue != isSimpleMemory )
0811             {
0812                 QApplication::beep();
0813                 return;
0814             }
0815             if ( isSimpleMemory )
0816                 simpleValue += simpleMemory;
0817             else
0818             {
0819                 referenceValue += referenceMemory;
0820                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0821             }
0822             break;
0823         case '-':
0824             if ( isSimpleValue != isSimpleMemory )
0825             {
0826                 QApplication::beep();
0827                 return;
0828             }
0829             if ( isSimpleMemory )
0830                 simpleValue -= simpleMemory;
0831             else
0832             {
0833                 referenceValue -= referenceMemory;
0834                 currencyValue = referenceValue * currencyRate * currencyPrecision;
0835             }
0836             break;
0837         case 'x':
0838             if ( isSimpleMemory )
0839             {
0840                 if ( isSimpleValue )
0841                     simpleValue *= simpleMemory;
0842                 else
0843                 {
0844                     referenceValue *= simpleMemory;
0845                     currencyValue = referenceValue * currencyRate * currencyPrecision;
0846                 }
0847             }
0848             else
0849             {
0850                 if ( isSimpleValue )
0851                 {
0852                     isSimpleValue = false;
0853                     referenceValue = simpleValue * referenceMemory;
0854                     currencyValue = referenceValue * currencyRate * currencyPrecision;
0855                 }
0856                 else
0857                 {
0858                     QApplication::beep();
0859                     return;
0860                 }
0861             }
0862             break;
0863         case '/':
0864             if ( isSimpleMemory )
0865             {
0866                 if ( simpleMemory == 0.0 )
0867                 {
0868                     QApplication::beep();
0869                     return;
0870                 }
0871                 if ( isSimpleValue )
0872                     simpleValue /= simpleMemory;
0873                 else
0874                 {
0875                     referenceValue /= simpleMemory;
0876                     currencyValue = referenceValue * currencyRate * currencyPrecision;
0877                 }
0878             }
0879             else
0880             {
0881                 if ( !isSimpleValue && referenceMemory != 0.0 )
0882                 {
0883                     isSimpleValue = true;
0884                     simpleValue = referenceValue / referenceMemory;
0885                 }
0886                 else
0887                 {
0888                     QApplication::beep();
0889                     return;
0890                 }
0891             }
0892     }
0893     resetInput();
0894     displayNewResult();
0895     displayMemoryButtons();
0896 }
0897 
0898 // Add memory to display
0899 void KEuroCalc::MemoryPlus()
0900 {
0901     if ( !memorySet || (isSimpleValue != isSimpleMemory) )
0902     {
0903         QApplication::beep();
0904         return;
0905     }
0906     if ( isSimpleMemory )
0907         simpleMemory += simpleValue;
0908     else
0909         referenceMemory += referenceValue;
0910 }
0911 
0912 // Subtract memory from display
0913 void KEuroCalc::MemoryMinus()
0914 {
0915     if ( !memorySet || (isSimpleValue != isSimpleMemory) )
0916     {
0917         QApplication::beep();
0918         return;
0919     }
0920     if ( isSimpleMemory )
0921         simpleMemory -= simpleValue;
0922     else
0923         referenceMemory -= referenceValue;
0924 }
0925 
0926 // Reset both input, result and memory
0927 void KEuroCalc::Reset()
0928 {
0929     resetInput();
0930 
0931     isSimpleValue = false;
0932     simpleValue = 0.0;
0933     referenceValue = 0.0;
0934     currencyValue = 0.0;
0935 
0936     displayNewResult();
0937 
0938     memorySet = false;
0939     isSimpleMemory = false;
0940     simpleMemory = 0.0;
0941     referenceMemory = 0.0;
0942 
0943     displayMemoryButtons();
0944 }
0945 
0946 // Display "about" page
0947 void KEuroCalc::DisplayAbout()
0948 {
0949     KAboutApplicationDialog *d = new KAboutApplicationDialog(KAboutData::applicationData(), this);
0950     d->exec();
0951     delete d;
0952     AboutButton->setDown( false );
0953 }
0954 
0955 // Display help pages
0956 void KEuroCalc::DisplayHelp()
0957 {
0958     KHelpClient::invokeHelp();
0959 }
0960 
0961 // Display settings pages
0962 void KEuroCalc::DisplaySettings()
0963 {
0964     Preferences *d = new Preferences(this, &currencies);
0965     d->exec();
0966     delete d;
0967     SettingsButton->setDown( false );
0968 }
0969 
0970 // Select currency accordingly to drop down list position
0971 void KEuroCalc::SelectCurrency(int position)
0972 {
0973     int num;
0974     double currencyRate, currencyPrecision;
0975 
0976     for (num = 0; num < currencies.number(); num++)
0977         if (currencies.position(num) == position)
0978             break;
0979     if ( num == currencies.number() ) return;
0980     currencyNum = num;
0981 
0982     displayNewCurrency();
0983 
0984     currencyRate = currencies.rate(currencyNum);
0985     switch (rounding)
0986     {
0987         case OFFICIAL_RULES:
0988             currencyPrecision = currencies.officialRulesPrecision(currencyNum);
0989             break;
0990         case SMALLEST_COIN:
0991             currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
0992             break;
0993         default:
0994             currencyPrecision = 1.0;
0995     }
0996     currencyValue = referenceValue * currencyRate * currencyPrecision;
0997     displayNewResult();
0998     setFocus();
0999 }
1000 
1001 // Initialize the buttons without translation and the buttons with UTF-8
1002 // text not correctly handled by uic
1003 void KEuroCalc::initButtons()
1004 {
1005     switch ( reference )
1006     {
1007         case EURO_FIXED:
1008             SourceLabel->setText( i18n( "Fixed" ) );
1009             DateLabel->setText( "" );
1010             break;
1011         case EURO_ECB:
1012             SourceLabel->setText( i18n( "ECB" ) );
1013             DateLabel->setText( i18n( "Loading..." ) );
1014             break;
1015 //      case DOLLAR_NY_FRB:
1016 //          SourceLabel->setText( i18n( "NY FRB" ) );
1017 //          DateLabel->setText( i18n( "Loading..." ) );
1018 //          break;
1019         case EURO_TG:
1020             SourceLabel->setText( i18n( "TG" ) );
1021             DateLabel->setText( i18n( "Loading..." ) );
1022     }
1023     switch ( rounding )
1024     {
1025         case OFFICIAL_RULES:
1026             RoundingLabel->setText( i18n( "Official rules" ) );
1027             break;
1028         case SMALLEST_COIN:
1029             RoundingLabel->setText( i18n( "Smallest coin" ) );
1030             break;
1031         case NO_ROUNDING:
1032             RoundingLabel->setText( i18n( "No rounding" ) );
1033     }
1034     DotButton->setText( QLocale().decimalPoint() );
1035     ZeroButton->setText( QString::fromUtf8( "0" ) );
1036     OneButton->setText( QString::fromUtf8( "1" ) );
1037     TwoButton->setText( QString::fromUtf8( "2" ) );
1038     ThreeButton->setText( QString::fromUtf8( "3" ) );
1039     FourButton->setText( QString::fromUtf8( "4" ) );
1040     FiveButton->setText( QString::fromUtf8( "5" ) );
1041     SixButton->setText( QString::fromUtf8( "6" ) );
1042     SevenButton->setText( QString::fromUtf8( "7" ) );
1043     EightButton->setText( QString::fromUtf8( "8" ) );
1044     NineButton->setText( QString::fromUtf8( "9" ) );
1045     BackspaceButton->setText( QString::fromUtf8( "<-" ) );
1046 
1047     MInputButton->setText( QString::fromUtf8( "Min" ) );
1048     MRecallButton->setText( QString::fromUtf8( "MR" ) );
1049     MMinusButton->setText( QString::fromUtf8( "M-" ) );
1050     MPlusButton->setText( QString::fromUtf8( "M+" ) );
1051     SlashButton->setText( QString::fromUtf8( "/" ) );
1052     AsteriskButton->setText( QString::fromUtf8( "X" ) );
1053     MinusButton->setText( QString::fromUtf8( "-" ) );
1054     PlusButton->setText( QString::fromUtf8( "+" ) );
1055 //  ReferenceButton->setText( QString::fromUtf8( reference == DOLLAR_NY_FRB? dollarSymbol: euroSymbol ) );
1056     ReferenceButton->setText( QString::fromUtf8( euroSymbol ) );
1057     PercentButton->setText( QString::fromUtf8( "%" ) );
1058     PlusMinusButton->setText( QString::fromUtf8( "+/-" ) );
1059 }
1060 
1061 // Start downloading rates
1062 void KEuroCalc::startDownload()
1063 {
1064     currencies.clearRates();
1065     switch (reference)
1066     {
1067         case EURO_FIXED:
1068             currencies.addFixedRates( rounding );
1069             // endDownload is called here
1070             break;
1071         case EURO_ECB:
1072             currencies.addFixedRates( rounding, true );
1073             // endDownload is called here for the first time
1074             CurrencyList->addItem( "--------------------------------------------" );
1075             currencies.addECBRates( rounding );
1076             // endDowload is called again when completed
1077             break;
1078 //      case DOLLAR_NY_FRB:
1079 //          currencies.addNY_FRBRates( rounding );
1080 //          // endDowload is called when completed
1081 //          break;
1082         case EURO_TG:
1083             currencies.addFixedRates( rounding, true );
1084             // endDownload is called here for the first time
1085             CurrencyList->addItem( "--------------------------------------------" );
1086             currencies.addTGRates( rounding );
1087             // endDowload is called again when completed
1088             break;
1089     }
1090 }
1091 
1092 // Download has ended
1093 void KEuroCalc::endDownload(int defaultCurrency, const QString &date)
1094 {
1095     int position, num;
1096 
1097     position = CurrencyList->count();
1098     for (num = 0; num < currencies.number(); ++num)
1099         if (currencies.position(num) == -2)
1100     {
1101         currencies.setPosition(num, position);
1102         CurrencyList->addItem
1103             ( currencies.code(num) + " - " + currencies.name(num) );
1104         position++;
1105     }
1106     DateLabel->setText( date.isNull()? i18n( "Not loaded" ): date );
1107     if ( defaultCurrency )
1108         newRatesList( defaultCurrency );
1109 }
1110 
1111 // The rates list has changed, refresh the display
1112 void KEuroCalc::newRatesList(int defaultCurrency)
1113 {
1114     int position;
1115 
1116     position = currencies.position(currencyNum);
1117     if (position < 0)                   // If current currency does not exist in new rates list, change current currency
1118     {
1119         for (currencyNum = 0; currencyNum < currencies.number(); ++currencyNum)
1120         {
1121             position = currencies.position(currencyNum);
1122             if (position == 0) break;
1123         }
1124         if ( currencyNum == currencies.number() )   // Handle case of empty list (no currencies at all)
1125         {
1126             currencyNum = defaultCurrency;
1127             currencies.setRate(currencyNum, 1.0);
1128             position = 0;
1129             currencies.setPosition(currencyNum, 0);
1130             CurrencyList->addItem
1131                 ( currencies.code(currencyNum) + " - " + currencies.name(currencyNum) );
1132         }
1133     }
1134     CurrencyList->setCurrentIndex( position );
1135     displayNewCurrency();
1136     displayNewResult();
1137 }
1138 
1139 // Input a digit ('0' to '9' or '.')
1140 void KEuroCalc::inputDigit(char c)
1141 {
1142     const char *s;
1143     char *d;
1144     switch ( inputPos )
1145     {
1146         case atUnits:
1147             inputDisplay[10] = c;
1148             switch ( c )
1149             {
1150                 case '.':
1151                     inputDisplay[9] = '0';
1152                     inputPos = afterUnits;
1153                     break;
1154                 case '0':
1155                     break;
1156                 default:
1157                     inputPos = beforeUnits;
1158             }
1159             break;
1160         case beforeUnits:
1161             if ( inputDisplay[0] != ' ' )
1162             {
1163                 QApplication::beep();
1164                 return;
1165             }
1166             s = inputDisplay + 1;
1167             d = inputDisplay;
1168             while ( d < inputDisplay + 10 ) *d++ = *s++;
1169             *d = c;
1170             if ( c == '.' ) inputPos = afterUnits;
1171             break;
1172         case afterUnits:
1173             if ( inputDisplay[0] != ' ' )
1174             {
1175                 QApplication::beep();
1176                 return;
1177             }
1178             if ( c == '.' )
1179             {
1180                 QApplication::beep();
1181                 return;
1182             }
1183             s = inputDisplay + 1;
1184             d = inputDisplay;
1185             while ( d < inputDisplay + 10 ) *d++ = *s++;
1186             *d = c;
1187             break;
1188         }
1189     displayNewInput();
1190 }
1191 
1192 // Remove last entered digit
1193 void KEuroCalc::inputCorrect()
1194 {
1195     const char *s;
1196     char *d;
1197 
1198     switch ( inputPos )
1199     {
1200         case atUnits:
1201             if ( inputDisplay[10] == ' ' )
1202                 *operatorDisplay = ' ';
1203             break;
1204         case beforeUnits:
1205         case afterUnits:
1206             s = inputDisplay + 9;
1207             d = inputDisplay + 10;
1208             while ( d > inputDisplay) *d-- = *s--;
1209             *d = ' ';
1210             break;
1211     }
1212     inputPos =
1213         inputDisplay[10] == ' '?
1214         atUnits:
1215         (QString(inputDisplay).indexOf('.') == -1? beforeUnits: afterUnits);
1216 
1217     displayNewInput();
1218 }
1219 
1220 // Input an operator ('+', '-', 'x' or '/')
1221 void KEuroCalc::inputOperator(char c)
1222 {
1223     if ( inputDisplay[10] != ' '  )
1224         ValidateSimpleValue();
1225 
1226     *operatorDisplay = c;
1227 
1228     displayNewInput();
1229 }
1230 
1231 // Reset input area
1232 void KEuroCalc::resetInput()
1233 {
1234     strcpy(operatorDisplay, " ");
1235     strcpy( inputDisplay, "           " );
1236     inputPos = atUnits;
1237     OperatorDisplay->setText( operatorDisplay );
1238     InputDisplay->setText( inputDisplay );
1239 }
1240 
1241 // Display current input in input area
1242 void KEuroCalc::displayNewInput()
1243 {
1244     QString display(inputDisplay);
1245     normalize( display );
1246 
1247     OperatorDisplay->setText( operatorDisplay );
1248     InputDisplay->setText( display );
1249 }
1250 
1251 // Display latest computed value in results area
1252 void KEuroCalc::displayNewResult()
1253 {
1254     if ( isSimpleValue )
1255     {
1256         QString simpleDisplay;
1257 
1258         simpleDisplay.setNum( simpleValue );
1259         normalize( simpleDisplay );
1260         ResultDisplay->setText( simpleDisplay );
1261     }
1262     else
1263     {
1264         double currencyPrecision;
1265         float roundedReferenceValue, roundedCurrencyValue;
1266         QString referenceDisplay, currencyDisplay;
1267         QString referenceSymbol, currencySymbol;
1268 
1269         if (rounding != NO_ROUNDING)
1270         {
1271             roundedReferenceValue = floor(referenceValue * 100.0 + 0.5) / 100.0;
1272             referenceDisplay.setNum( roundedReferenceValue, 'f', 2 );
1273         }
1274         else referenceDisplay.setNum( referenceValue );
1275         normalize( referenceDisplay );
1276 //      referenceSymbol = QString::fromUtf8( reference == DOLLAR_NY_FRB ? dollarSymbol: euroSymbol );
1277         referenceSymbol = QString::fromUtf8( euroSymbol );
1278 
1279         switch (rounding)
1280         {
1281             case OFFICIAL_RULES:
1282                 currencyPrecision = currencies.officialRulesPrecision(currencyNum);
1283                 roundedCurrencyValue = floor(currencyValue * 100.0 / currencyPrecision + 0.5)
1284                              / 100.0 * currencyPrecision;
1285                 currencyDisplay.setNum( roundedCurrencyValue, 'f', currencyPrecision < 100.0? 2: 0 );
1286                 break;
1287             case SMALLEST_COIN:
1288                 currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
1289                 roundedCurrencyValue = floor(currencyValue * 100.0 / currencyPrecision + 0.5)
1290                              / 100.0 * currencyPrecision;
1291                 currencyDisplay.setNum( roundedCurrencyValue, 'f', currencyPrecision < 100.0? 2: 0 );
1292                 break;
1293             default:
1294                 currencyDisplay.setNum( currencyValue );
1295         }
1296         normalize( currencyDisplay );
1297         currencySymbol = currencies.symbol(currencyNum);
1298 
1299         ResultDisplay->setText( referenceDisplay + referenceSymbol + '\n' +
1300                     currencyDisplay + ' ' + currencySymbol );
1301     }
1302 }
1303 
1304 // Update the currency button accordingly to new currency
1305 void KEuroCalc::displayNewCurrency()
1306 {
1307     QString referenceSymbol, currencySymbol;
1308 
1309     currencySymbol = currencies.symbol(currencyNum);
1310     CurrencyButton->setText( currencySymbol );
1311     if ( currencies.position(currencyNum) >= 0 )
1312     {
1313         double currencyRate, currencyPrecision;
1314         QString rate;
1315 
1316         currencyRate = currencies.rate(currencyNum);
1317         switch (rounding)
1318         {
1319             case OFFICIAL_RULES:
1320                 currencyPrecision = currencies.officialRulesPrecision(currencyNum);
1321                 break;
1322             case SMALLEST_COIN:
1323                 currencyPrecision = currencies.smallestCoinPrecision(currencyNum);
1324                 break;
1325             default:
1326                 currencyPrecision = 1.0;
1327         }
1328         rate.setNum( currencyRate * currencyPrecision ); 
1329 //      referenceSymbol = QString::fromUtf8( reference == DOLLAR_NY_FRB ? dollarSymbol: euroSymbol );
1330         referenceSymbol = QString::fromUtf8( euroSymbol );
1331         RateLabel->setText
1332             ( '1' + referenceSymbol + " = " + rate + ' ' + currencySymbol ); 
1333     }
1334     else RateLabel->setText( "" );
1335 }
1336 
1337 // Display the memory Plus and Minus buttons
1338 void KEuroCalc::displayMemoryButtons()
1339 {
1340     bool recallEnabled = memorySet,
1341          sumsEnabled = memorySet && (isSimpleValue == isSimpleMemory);
1342 
1343     MRecallButton->setEnabled( recallEnabled );
1344     MMinusButton->setEnabled( sumsEnabled );
1345     MPlusButton->setEnabled( sumsEnabled );
1346 }
1347 
1348 // Normalize the display of a number
1349 void KEuroCalc::normalize( QString &numberDisplay )
1350 {
1351     int dotPos = numberDisplay.indexOf('.'),
1352         unitPos = (dotPos == -1? numberDisplay.length(): dotPos) - 3;
1353 
1354     if ( dotPos != -1 )
1355         numberDisplay.replace(  dotPos,
1356                     1,
1357                     QLocale().decimalPoint() );
1358 
1359     while (unitPos > 0)
1360     {
1361         numberDisplay.insert(   unitPos,
1362                     " ");
1363         unitPos -= 3;
1364     }
1365 }
1366 
1367 #include "moc_keurocalc.cpp"