1 /*
2     SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
3     SPDX-FileCopyrightText: 2006 Michel Marti <mma@objectxp.com>
4     SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "kcalc.h"
10 #include "kcalc_version.h"
11 
12 #include <clocale>
13 
14 #include <QActionGroup>
15 #include <QApplication>
16 #include <QButtonGroup>
17 #include <QCommandLineParser>
18 #include <QCursor>
19 #include <QKeyEvent>
20 #include <QMenuBar>
21 #include <QShortcut>
22 #include <QStyle>
23 
24 #include <kxmlgui_version.h>
25 #include <KAboutData>
26 #include <KAcceleratorManager>
27 #include <KActionCollection>
28 #include <KColorMimeData>
29 #include <KConfigDialog>
30 #include <KCrash>
31 #include <KStandardAction>
32 #include <KToggleAction>
33 #include <KToolBar>
34 #include <KXMLGUIFactory>
35 #include <Kdelibs4ConfigMigrator>
36 
37 #include "kcalc_bitset.h"
38 #include "kcalc_const_menu.h"
39 #include "kcalc_settings.h"
40 #include "kcalc_statusbar.h"
41 #include "kcalcdisplay.h"
42 #include "kcalchistory.h"
43 
44 namespace
45 {
46 const char description[] = I18N_NOOP("KDE Calculator");
47 const int maxprecision = 1000;
48 }
49 
50 //------------------------------------------------------------------------------
51 // Name: KCalculator
52 // Desc: constructor
53 //------------------------------------------------------------------------------
KCalculator(QWidget * parent)54 KCalculator::KCalculator(QWidget *parent)
55     : KXmlGuiWindow(parent)
56     , memory_num_(0.0)
57     , core()
58 {
59     // central widget to contain all the elements
60     auto const central = new QWidget(this);
61     central->setLayoutDirection(Qt::LeftToRight);
62     setCentralWidget(central);
63     KAcceleratorManager::setNoAccel(central);
64 
65     // load science constants_ from xml-file
66     KCalcConstMenu::init_consts();
67 
68     // setup interface (order is critical)
69     setupUi(central);
70     setupMainActions();
71     setStatusBar(new KCalcStatusBar(this));
72     createGUI();
73     setupKeys();
74 
75     toolBar()->hide(); // hide by default
76 
77     // create button groups
78     base_choose_group_ = new QButtonGroup(this);
79     base_choose_group_->setExclusive(true);
80     base_choose_group_->addButton(hexRadio, HexMode);
81     base_choose_group_->addButton(decRadio, DecMode);
82     base_choose_group_->addButton(octRadio, OctMode);
83     base_choose_group_->addButton(binRadio, BinMode);
84     connect(base_choose_group_, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KCalculator::slotBaseSelected);
85 
86     base_conversion_labels_ = {binDisplay, hexDisplay, decDisplay, octDisplay};
87 
88     angle_choose_group_ = new QButtonGroup(this);
89     angle_choose_group_->
90     setExclusive(true);
91     angle_choose_group_->addButton(degRadio, DegMode);
92     angle_choose_group_->addButton(radRadio, RadMode);
93     angle_choose_group_->addButton(gradRadio, GradMode);
94     connect(angle_choose_group_, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KCalculator::slotAngleSelected);
95 
96     // additional menu setup
97     constants_menu_ = createConstantsMenu();
98     menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
99 
100     // misc setup
101     setColors();
102     setFonts();
103 
104     // Show the result in the app's caption in taskbar (wishlist - bug #52858)
105     if (KCalcSettings::captionResult() == true) {
106         connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle);
107     }
108 
109     calc_display->changeSettings();
110     calc_history->changeSettings();
111     update_history_window_ = true;
112     setPrecision();
113 
114     updateGeometry();
115 
116     layout()->setSizeConstraint(QLayout::SetFixedSize);
117 
118     updateDisplay(UPDATE_FROM_CORE);
119     // clear history, otherwise we have a leading "0" in it
120     calc_history->clearHistory();
121 
122     // misc settings
123     KCalcSettings::EnumCalculatorMode::type calculatorMode = KCalcSettings::calculatorMode();
124 
125     switch (calculatorMode) {
126     case KCalcSettings::EnumCalculatorMode::science:
127         action_mode_science_->setChecked(true);
128         break;
129     case KCalcSettings::EnumCalculatorMode::statistics:
130         action_mode_statistic_->setChecked(true);
131         break;
132     case KCalcSettings::EnumCalculatorMode::numeral:
133         action_mode_numeral_->setChecked(true);
134         break;
135     case KCalcSettings::EnumCalculatorMode::simple:
136     default:
137         action_mode_simple_->setChecked(true);
138     }
139 
140     setAngle();
141     setBase();
142 
143     calc_display->setFocus();
144 }
145 
146 //------------------------------------------------------------------------------
147 // Name: ~KCalculator
148 // Desc: deconstructor
149 //------------------------------------------------------------------------------
~KCalculator()150 KCalculator::~KCalculator()
151 {
152     KCalcSettings::self()->save();
153 }
154 
155 //------------------------------------------------------------------------------
156 // Name: setupMainActions
157 // Desc: connects all of the basic actions
158 //------------------------------------------------------------------------------
setupMainActions()159 void KCalculator::setupMainActions()
160 {
161     // file menu
162     KStandardAction::quit(this, SLOT(close()), actionCollection());
163 
164     // edit menu
165     KStandardAction::undo(calc_display, SLOT(slotHistoryBack()), actionCollection());
166     KStandardAction::redo(calc_display, SLOT(slotHistoryForward()), actionCollection());
167     KStandardAction::cut(calc_display, SLOT(slotCut()), actionCollection());
168     KStandardAction::copy(calc_display, SLOT(slotCopy()), actionCollection());
169     KStandardAction::paste(this, SLOT(slotPaste()), actionCollection());
170 
171     // mode menu
172     auto modeGroup = new QActionGroup(this);
173 
174     action_mode_simple_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_simple"));
175     action_mode_simple_->setActionGroup(modeGroup);
176     action_mode_simple_->setText(i18n("Simple Mode"));
177     connect(action_mode_simple_, &KToggleAction::toggled, this, &KCalculator::slotSetSimpleMode);
178 
179     action_mode_science_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_science"));
180     action_mode_science_->setActionGroup(modeGroup);
181     action_mode_science_->setText(i18n("Science Mode"));
182     connect(action_mode_science_, &KToggleAction::toggled, this, &KCalculator::slotSetScienceMode);
183 
184     action_mode_statistic_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_statistics"));
185     action_mode_statistic_->setActionGroup(modeGroup);
186     action_mode_statistic_->setText(i18n("Statistic Mode"));
187     connect(action_mode_statistic_, &KToggleAction::toggled, this, &KCalculator::slotSetStatisticMode);
188 
189     action_mode_numeral_ = actionCollection()->add<KToggleAction>(QStringLiteral("mode_numeral"));
190     action_mode_numeral_->setActionGroup(modeGroup);
191     action_mode_numeral_->setText(i18n("Numeral System Mode"));
192     connect(action_mode_numeral_, &KToggleAction::toggled, this, &KCalculator::slotSetNumeralMode);
193 
194     // settings menu
195     action_history_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_history"));
196     action_history_show_->setText(i18n("Show &History"));
197     action_history_show_->setChecked(true);
198     actionCollection()->setDefaultShortcut(action_history_show_, Qt::CTRL | Qt::Key_H);
199     connect(action_history_show_, &KToggleAction::toggled, this, &KCalculator::slotHistoryshow);
200 
201     action_constants_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_constants"));
202     action_constants_show_->setText(i18n("Constants &Buttons"));
203     action_constants_show_->setChecked(true);
204     connect(action_constants_show_, &KToggleAction::toggled, this, &KCalculator::slotConstantsShow);
205 
206     action_bitset_show_ = actionCollection()->add<KToggleAction>(QStringLiteral("show_bitset"));
207     action_bitset_show_->setText(i18n("Show B&it Edit"));
208     action_bitset_show_->setChecked(true);
209     connect(action_bitset_show_, &KToggleAction::toggled, this, &KCalculator::slotBitsetshow);
210 
211     KStandardAction::preferences(this, &KCalculator::showSettings, actionCollection());
212 
213     KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
214 }
215 
216 //------------------------------------------------------------------------------
217 // Name: createConstantsMenu
218 // Desc: creates and returns a pointer to the constant menu
219 //------------------------------------------------------------------------------
createConstantsMenu()220 KCalcConstMenu *KCalculator::createConstantsMenu()
221 {
222     auto const menu = new KCalcConstMenu(i18n("&Constants"), this);
223     connect(menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotConstantToDisplay);
224     return menu;
225 }
226 
227 //------------------------------------------------------------------------------
228 // Name: statusBar
229 // Desc: returns a pointer to the status bar
230 //------------------------------------------------------------------------------
statusBar()231 KCalcStatusBar *KCalculator::statusBar()
232 {
233     return static_cast<KCalcStatusBar *>(KXmlGuiWindow::statusBar());
234 }
235 
236 //------------------------------------------------------------------------------
237 // Name: setupNumberKeys
238 // Desc: sets up number keys and related shortcuts
239 //------------------------------------------------------------------------------
setupNumberKeys()240 void KCalculator::setupNumberKeys()
241 {
242     num_button_group_ = new QButtonGroup(this);
243     connect(num_button_group_, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KCalculator::slotNumberclicked);
244 
245     num_button_group_->addButton(pb0, 0);
246     num_button_group_->addButton(pb1, 1);
247     num_button_group_->addButton(pb2, 2);
248     num_button_group_->addButton(pb3, 3);
249     num_button_group_->addButton(pb4, 4);
250     num_button_group_->addButton(pb5, 5);
251     num_button_group_->addButton(pb6, 6);
252     num_button_group_->addButton(pb7, 7);
253     num_button_group_->addButton(pb8, 8);
254     num_button_group_->addButton(pb9, 9);
255     num_button_group_->addButton(pbA, 0xA);
256     num_button_group_->addButton(pbB, 0xB);
257     num_button_group_->addButton(pbC, 0xC);
258     num_button_group_->addButton(pbD, 0xD);
259     num_button_group_->addButton(pbE, 0xE);
260     num_button_group_->addButton(pbF, 0xF);
261     connect(this, &KCalculator::switchShowAccels, pb0, &KCalcButton::slotSetAccelDisplayMode);
262     connect(this, &KCalculator::switchShowAccels, pb1, &KCalcButton::slotSetAccelDisplayMode);
263     connect(this, &KCalculator::switchShowAccels, pb2, &KCalcButton::slotSetAccelDisplayMode);
264     connect(this, &KCalculator::switchShowAccels, pb3, &KCalcButton::slotSetAccelDisplayMode);
265     connect(this, &KCalculator::switchShowAccels, pb4, &KCalcButton::slotSetAccelDisplayMode);
266     connect(this, &KCalculator::switchShowAccels, pb5, &KCalcButton::slotSetAccelDisplayMode);
267     connect(this, &KCalculator::switchShowAccels, pb6, &KCalcButton::slotSetAccelDisplayMode);
268     connect(this, &KCalculator::switchShowAccels, pb7, &KCalcButton::slotSetAccelDisplayMode);
269     connect(this, &KCalculator::switchShowAccels, pb8, &KCalcButton::slotSetAccelDisplayMode);
270     connect(this, &KCalculator::switchShowAccels, pb9, &KCalcButton::slotSetAccelDisplayMode);
271     connect(this, &KCalculator::switchShowAccels, pbA, &KCalcButton::slotSetAccelDisplayMode);
272     connect(this, &KCalculator::switchShowAccels, pbB, &KCalcButton::slotSetAccelDisplayMode);
273     connect(this, &KCalculator::switchShowAccels, pbC, &KCalcButton::slotSetAccelDisplayMode);
274     connect(this, &KCalculator::switchShowAccels, pbD, &KCalcButton::slotSetAccelDisplayMode);
275     connect(this, &KCalculator::switchShowAccels, pbE, &KCalcButton::slotSetAccelDisplayMode);
276     connect(this, &KCalculator::switchShowAccels, pbF, &KCalcButton::slotSetAccelDisplayMode);
277 }
278 
279 //------------------------------------------------------------------------------
280 // Name: setupRightKeypad
281 // Desc: sets up right keypad keys and related shortcuts
282 //------------------------------------------------------------------------------
setupRightKeypad()283 void KCalculator::setupRightKeypad()
284 {
285     connect(pbShift, &KCalcButton::toggled, this, &KCalculator::slotShifttoggled);
286     connect(this, &KCalculator::switchShowAccels, pbShift, &KCalcButton::slotSetAccelDisplayMode);
287 
288     pbBackspace->setShortcut(QKeySequence(Qt::Key_Backspace));
289     new QShortcut(Qt::Key_PageUp, pbBackspace, SLOT(animateClick()));
290     connect(pbBackspace, &KCalcButton::clicked, this, &KCalculator::slotBackspaceclicked);
291     connect(this, &KCalculator::switchShowAccels, pbBackspace, &KCalcButton::slotSetAccelDisplayMode);
292 
293     pbClear->setShortcut(QKeySequence(Qt::Key_Escape));
294     new QShortcut(Qt::Key_PageUp, pbClear, SLOT(animateClick()));
295     connect(pbClear, &KCalcButton::clicked, this, &KCalculator::slotClearclicked);
296     connect(this, &KCalculator::switchShowAccels, pbClear, &KCalcButton::slotSetAccelDisplayMode);
297 
298     pbAllClear->setShortcut(QKeySequence(Qt::Key_Delete));
299     new QShortcut(Qt::Key_PageDown, pbAllClear, SLOT(animateClick()));
300     connect(pbAllClear, &KCalcButton::clicked, this, &KCalculator::slotAllClearclicked);
301     connect(this, &KCalculator::switchShowAccels, pbAllClear, &KCalcButton::slotSetAccelDisplayMode);
302     // also clear the content of the history when clicked
303     connect(pbAllClear, &KCalcButton::clicked, calc_history, &KCalcHistory::clearHistory);
304 
305     pbParenOpen->setShortcut(QKeySequence(Qt::Key_ParenLeft));
306     connect(pbParenOpen, &KCalcButton::clicked, this, &KCalculator::slotParenOpenclicked);
307     connect(this, &KCalculator::switchShowAccels, pbParenOpen, &KCalcButton::slotSetAccelDisplayMode);
308 
309     pbParenClose->setShortcut(QKeySequence(Qt::Key_ParenRight));
310     connect(pbParenClose, &KCalcButton::clicked, this, &KCalculator::slotParenCloseclicked);
311     connect(this, &KCalculator::switchShowAccels, pbParenClose, &KCalcButton::slotSetAccelDisplayMode);
312 
313     pbMemRecall->setDisabled(true); // nothing in memory at start
314     connect(pbMemRecall, &KCalcButton::clicked, this, &KCalculator::slotMemRecallclicked);
315     connect(this, &KCalculator::switchShowAccels, pbMemRecall, &KCalcButton::slotSetAccelDisplayMode);
316 
317     connect(pbMemClear, &KCalcButton::clicked, this, &KCalculator::slotMemClearclicked);
318     connect(this, &KCalculator::switchShowAccels, pbMemClear, &KCalcButton::slotSetAccelDisplayMode);
319 
320     pbMemPlusMinus->addMode(ModeNormal, i18nc("Add display to memory", "M+"), i18n("Add display to memory"));
321     pbMemPlusMinus->addMode(ModeShift, i18nc("Subtract from memory", "M\xe2\x88\x92"), i18n("Subtract from memory"));
322     connect(pbMemPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotMemPlusMinusclicked);
323     connect(this, &KCalculator::switchShowAccels, pbMemPlusMinus, &KCalcButton::slotSetAccelDisplayMode);
324     connect(this, &KCalculator::switchMode, pbMemPlusMinus, &KCalcButton::slotSetMode);
325 
326     connect(pbMemStore, &KCalcButton::clicked, this, &KCalculator::slotMemStoreclicked);
327     connect(this, &KCalculator::switchShowAccels, pbMemStore, &KCalcButton::slotSetAccelDisplayMode);
328 
329     pbPercent->setShortcut(QKeySequence(Qt::Key_Percent));
330     connect(pbPercent, &KCalcButton::clicked, this, &KCalculator::slotPercentclicked);
331     connect(this, &KCalculator::switchShowAccels, pbPercent, &KCalcButton::slotSetAccelDisplayMode);
332 
333     pbPlusMinus->setShortcut(QKeySequence(Qt::Key_Backslash));
334     connect(pbPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotPlusMinusclicked);
335     connect(this, &KCalculator::switchShowAccels, pbPlusMinus, &KCalcButton::slotSetAccelDisplayMode);
336 }
337 
338 //------------------------------------------------------------------------------
339 // Name: setupNumericKeypad
340 // Desc: sets up numeric keys and related shortcuts
341 //------------------------------------------------------------------------------
setupNumericKeypad()342 void KCalculator::setupNumericKeypad()
343 {
344     pbCube->addMode(ModeNormal, i18nc("Third power", "x<sup>3</sup>"), i18n("Third power"));
345     pbCube->addMode(ModeShift, QStringLiteral("<sup>3</sup>&radic;x"), i18n("Cube root"));
346     connect(pbCube, &KCalcButton::clicked, this, &KCalculator::slotCubeclicked);
347     connect(this, &KCalculator::switchShowAccels, pbCube, &KCalcButton::slotSetAccelDisplayMode);
348     connect(this, &KCalculator::switchMode, pbCube, &KCalcButton::slotSetMode);
349 
350     pbDivision->setShortcut(QKeySequence(Qt::Key_Slash));
351     new QShortcut(Qt::Key_division, pbDivision, SLOT(animateClick()));
352     connect(pbDivision, &KCalcButton::clicked, this, &KCalculator::slotDivisionclicked);
353     connect(this, &KCalculator::switchShowAccels, pbDivision, &KCalcButton::slotSetAccelDisplayMode);
354 
355     pbMultiplication->setShortcut(QKeySequence(Qt::Key_Asterisk));
356     new QShortcut(Qt::Key_X, pbMultiplication, SLOT(animateClick()));
357     new QShortcut(Qt::Key_multiply, pbMultiplication, SLOT(animateClick()));
358     connect(pbMultiplication, &KCalcButton::clicked, this, &KCalculator::slotMultiplicationclicked);
359     connect(this, &KCalculator::switchShowAccels, pbMultiplication, &KCalcButton::slotSetAccelDisplayMode);
360 
361     pbMinus->setShortcut(QKeySequence(Qt::Key_Minus));
362     connect(pbMinus, &KCalcButton::clicked, this, &KCalculator::slotMinusclicked);
363     connect(this, &KCalculator::switchShowAccels, pbMinus, &KCalcButton::slotSetAccelDisplayMode);
364 
365     pbPlus->setShortcut(QKeySequence(Qt::Key_Plus));
366     connect(pbPlus, &KCalcButton::clicked, this, &KCalculator::slotPlusclicked);
367     connect(this, &KCalculator::switchShowAccels, pbPlus, &KCalcButton::slotSetAccelDisplayMode);
368 
369     // set decimal separator from locale
370     pbPeriod->setText(QString(QLocale().decimalPoint()));
371     pbPeriod->setShortcut(QString(QLocale().decimalPoint()));
372 
373     // add shortcut for the other decimal separator (point or comma)
374     if (QLocale().decimalPoint() == QLatin1Char('.')) {
375         new QShortcut(Qt::Key_Comma, pbPeriod, SLOT(animateClick()));
376     } else if (QLocale().decimalPoint() == QLatin1Char(',')) {
377         new QShortcut(Qt::Key_Period, pbPeriod, SLOT(animateClick()));
378     }
379 
380     connect(pbPeriod, &KCalcButton::clicked, this, &KCalculator::slotPeriodclicked);
381     connect(this, &KCalculator::switchShowAccels, pbPeriod, &KCalcButton::slotSetAccelDisplayMode);
382 
383     pbEqual->setShortcut(QKeySequence(Qt::Key_Enter));
384     new QShortcut(Qt::Key_Equal, pbEqual, SLOT(animateClick()));
385     new QShortcut(Qt::Key_Return, pbEqual, SLOT(animateClick()));
386     connect(pbEqual, &KCalcButton::clicked, this, &KCalculator::slotEqualclicked);
387     connect(this, &KCalculator::switchShowAccels, pbEqual, &KCalcButton::slotSetAccelDisplayMode);
388 }
389 
390 //------------------------------------------------------------------------------
391 // Name: setupLogicKeys
392 // Desc: sets up logic keys and related shortcuts
393 //------------------------------------------------------------------------------
setupLogicKeys()394 void KCalculator::setupLogicKeys()
395 {
396     logic_buttons_.append(pbAND);
397     logic_buttons_.append(pbOR);
398     logic_buttons_.append(pbXOR);
399     logic_buttons_.append(pbLsh);
400     logic_buttons_.append(pbRsh);
401     logic_buttons_.append(pbCmp);
402 
403     pbAND->setShortcut(QKeySequence(Qt::Key_Ampersand));
404     connect(this, &KCalculator::switchShowAccels, pbAND, &KCalcButton::slotSetAccelDisplayMode);
405     connect(pbAND, &KCalcButton::clicked, this, &KCalculator::slotANDclicked);
406 
407     pbOR->setShortcut(QKeySequence(Qt::Key_Bar));
408     connect(this, &KCalculator::switchShowAccels, pbOR, &KCalcButton::slotSetAccelDisplayMode);
409     connect(pbOR, &KCalcButton::clicked, this, &KCalculator::slotORclicked);
410 
411     connect(this, &KCalculator::switchShowAccels, pbXOR, &KCalcButton::slotSetAccelDisplayMode);
412     connect(pbXOR, &KCalcButton::clicked, this, &KCalculator::slotXORclicked);
413 
414     pbLsh->setShortcut(QKeySequence(Qt::Key_Less));
415     connect(this, &KCalculator::switchShowAccels, pbLsh, &KCalcButton::slotSetAccelDisplayMode);
416     connect(pbLsh, &KCalcButton::clicked, this, &KCalculator::slotLeftShiftclicked);
417 
418     pbRsh->setShortcut(QKeySequence(Qt::Key_Greater));
419     connect(this, &KCalculator::switchShowAccels, pbRsh, &KCalcButton::slotSetAccelDisplayMode);
420     connect(pbRsh, &KCalcButton::clicked, this, &KCalculator::slotRightShiftclicked);
421 
422     pbCmp->setShortcut(QKeySequence(Qt::Key_AsciiTilde));
423     connect(this, &KCalculator::switchShowAccels, pbCmp, &KCalcButton::slotSetAccelDisplayMode);
424     connect(pbCmp, &KCalcButton::clicked, this, &KCalculator::slotNegateclicked);
425 }
426 
427 //------------------------------------------------------------------------------
428 // Name: setupLogicKeys
429 // Desc: sets up scientific keys and related shortcuts
430 //------------------------------------------------------------------------------
setupScientificKeys()431 void KCalculator::setupScientificKeys()
432 {
433     scientific_buttons_.append(pbHyp);
434     scientific_buttons_.append(pbSin);
435     scientific_buttons_.append(pbCos);
436     scientific_buttons_.append(pbTan);
437     scientific_buttons_.append(pbLog);
438     scientific_buttons_.append(pbLn);
439 
440     connect(this, &KCalculator::switchShowAccels, pbHyp, &KCalcButton::slotSetAccelDisplayMode);
441     connect(pbHyp, &KCalcButton::toggled, this, &KCalculator::slotHyptoggled);
442 
443     pbSin->addMode(ModeNormal, i18nc("Sine", "sin"), i18n("Sine"));
444     pbSin->addMode(ModeShift, i18nc("Arc sine", "asin"), i18n("Arc sine"));
445     pbSin->addMode(ModeHyperbolic, i18nc("Hyperbolic sine", "sinh"), i18n("Hyperbolic sine"));
446     pbSin->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic sine", "asinh"), i18n("Inverse hyperbolic sine"));
447     connect(this, &KCalculator::switchShowAccels, pbSin, &KCalcButton::slotSetAccelDisplayMode);
448     connect(this, &KCalculator::switchMode, pbSin, &KCalcButton::slotSetMode);
449     connect(pbSin, &KCalcButton::clicked, this, &KCalculator::slotSinclicked);
450 
451     pbCos->addMode(ModeNormal, i18nc("Cosine", "cos"), i18n("Cosine"));
452     pbCos->addMode(ModeShift, i18nc("Arc cosine", "acos"), i18n("Arc cosine"));
453     pbCos->addMode(ModeHyperbolic, i18nc("Hyperbolic cosine", "cosh"), i18n("Hyperbolic cosine"));
454     pbCos->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic cosine", "acosh"), i18n("Inverse hyperbolic cosine"));
455     connect(this, &KCalculator::switchShowAccels, pbCos, &KCalcButton::slotSetAccelDisplayMode);
456     connect(this, &KCalculator::switchMode, pbCos, &KCalcButton::slotSetMode);
457     connect(pbCos, &KCalcButton::clicked, this, &KCalculator::slotCosclicked);
458 
459     pbTan->addMode(ModeNormal, i18nc("Tangent", "tan"), i18n("Tangent"));
460     pbTan->addMode(ModeShift, i18nc("Arc tangent", "atan"), i18n("Arc tangent"));
461     pbTan->addMode(ModeHyperbolic, i18nc("Hyperbolic tangent", "tanh"), i18n("Hyperbolic tangent"));
462     pbTan->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic tangent", "atanh"), i18n("Inverse hyperbolic tangent"));
463     connect(this, &KCalculator::switchShowAccels, pbTan, &KCalcButton::slotSetAccelDisplayMode);
464     connect(this, &KCalculator::switchMode, pbTan, &KCalcButton::slotSetMode);
465     connect(pbTan, &KCalcButton::clicked, this, &KCalculator::slotTanclicked);
466 
467     pbLog->addMode(ModeNormal, i18nc("Logarithm to base 10", "log"), i18n("Logarithm to base 10"));
468     pbLog->addMode(ModeShift, i18nc("10 to the power of x", "10<sup>x</sup>"), i18n("10 to the power of x"));
469     connect(this, &KCalculator::switchShowAccels, pbLog, &KCalcButton::slotSetAccelDisplayMode);
470     connect(this, &KCalculator::switchMode, pbLog, &KCalcButton::slotSetMode);
471     connect(pbLog, &KCalcButton::clicked, this, &KCalculator::slotLogclicked);
472     pbLn->addMode(ModeNormal, i18nc("Natural log", "ln"), i18n("Natural log"));
473     pbLn->addMode(ModeShift, i18nc("Exponential function", "e<sup>x</sup>"), i18n("Exponential function"));
474     connect(this, &KCalculator::switchShowAccels, pbLn, &KCalcButton::slotSetAccelDisplayMode);
475     connect(this, &KCalculator::switchMode, pbLn, &KCalcButton::slotSetMode);
476     connect(pbLn, &KCalcButton::clicked, this, &KCalculator::slotLnclicked);
477 }
478 
479 //------------------------------------------------------------------------------
480 // Name: setupStatisticKeys
481 // Desc: sets up statistical keys and related shortcuts
482 //------------------------------------------------------------------------------
setupStatisticKeys()483 void KCalculator::setupStatisticKeys()
484 {
485     stat_buttons_.append(pbNData);
486     stat_buttons_.append(pbMean);
487     stat_buttons_.append(pbSd);
488     stat_buttons_.append(pbMed);
489     stat_buttons_.append(pbDat);
490     stat_buttons_.append(pbCSt);
491 
492     pbNData->addMode(ModeNormal, i18nc("Number of data entered", "N"), i18n("Number of data entered"));
493     pbNData->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1Char('x'), i18n("Sum of all data items"));
494     connect(this, &KCalculator::switchShowAccels, pbNData, &KCalcButton::slotSetAccelDisplayMode);
495     connect(this, &KCalculator::switchMode, pbNData, &KCalcButton::slotSetMode);
496     connect(pbNData, &KCalcButton::clicked, this, &KCalculator::slotStatNumclicked);
497 
498     pbMean->addMode(ModeNormal, i18nc("Mean", "Mea"), i18n("Mean"));
499     pbMean->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1String("x<sup>2</sup>"), i18n("Sum of all data items squared"));
500     connect(this, &KCalculator::switchShowAccels, pbMean, &KCalcButton::slotSetAccelDisplayMode);
501     connect(this, &KCalculator::switchMode, pbMean, &KCalcButton::slotSetMode);
502     connect(pbMean, &KCalcButton::clicked, this, &KCalculator::slotStatMeanclicked);
503 
504     pbSd->addMode(ModeNormal, QString::fromUtf8("\xcf\x83") + QLatin1String("<sub>N</sub>"), i18n("Standard deviation"));
505     pbSd->addMode(ModeShift, QString::fromUtf8("\xcf\x83") + QLatin1String("<sub>N-1</sub>"), i18n("Sample standard deviation"));
506     connect(this, &KCalculator::switchShowAccels, pbSd, &KCalcButton::slotSetAccelDisplayMode);
507     connect(this, &KCalculator::switchMode, pbSd, &KCalcButton::slotSetMode);
508     connect(pbSd, &KCalcButton::clicked, this, &KCalculator::slotStatStdDevclicked);
509 
510     connect(this, &KCalculator::switchShowAccels, pbMed, &KCalcButton::slotSetAccelDisplayMode);
511     connect(pbMed, &KCalcButton::clicked, this, &KCalculator::slotStatMedianclicked);
512 
513     pbDat->addMode(ModeNormal, i18nc("Enter data", "Dat"), i18n("Enter data"));
514     pbDat->addMode(ModeShift, i18nc("Delete last data item", "CDat"), i18n("Delete last data item"));
515     connect(this, &KCalculator::switchShowAccels, pbDat, &KCalcButton::slotSetAccelDisplayMode);
516     connect(this, &KCalculator::switchMode, pbDat, &KCalcButton::slotSetMode);
517     connect(pbDat, &KCalcButton::clicked, this, &KCalculator::slotStatDataInputclicked);
518 
519     connect(this, &KCalculator::switchShowAccels, pbCSt, &KCalcButton::slotSetAccelDisplayMode);
520     connect(pbCSt, &KCalcButton::clicked, this, &KCalculator::slotStatClearDataclicked);
521 }
522 
523 //------------------------------------------------------------------------------
524 // Name: setupConstantsKeys
525 // Desc: sets up constants keys and related shortcuts
526 //------------------------------------------------------------------------------
setupConstantsKeys()527 void KCalculator::setupConstantsKeys()
528 {
529     const_buttons_.append(pbC1);
530     const_buttons_.append(pbC2);
531     const_buttons_.append(pbC3);
532     const_buttons_.append(pbC4);
533     const_buttons_.append(pbC5);
534     const_buttons_.append(pbC6);
535 
536     pbC1->setButtonNumber(0);
537     connect(this, &KCalculator::switchShowAccels, pbC1, &KCalcConstButton::slotSetAccelDisplayMode);
538     connect(this, &KCalculator::switchMode, pbC1, &KCalcConstButton::slotSetMode);
539     connect(pbC1, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
540 
541     pbC2->setButtonNumber(1);
542     connect(this, &KCalculator::switchShowAccels, pbC2, &KCalcConstButton::slotSetAccelDisplayMode);
543     connect(this, &KCalculator::switchMode, pbC2, &KCalcConstButton::slotSetMode);
544     connect(pbC2, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
545 
546     pbC3->setButtonNumber(2);
547     connect(this, &KCalculator::switchShowAccels, pbC3, &KCalcConstButton::slotSetAccelDisplayMode);
548     connect(this, &KCalculator::switchMode, pbC3, &KCalcConstButton::slotSetMode);
549     connect(pbC3, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
550 
551     pbC4->setButtonNumber(3);
552     connect(this, &KCalculator::switchShowAccels, pbC4, &KCalcConstButton::slotSetAccelDisplayMode);
553     connect(this, &KCalculator::switchMode, pbC4, &KCalcConstButton::slotSetMode);
554     connect(pbC4, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
555 
556     pbC5->setButtonNumber(4);
557     connect(this, &KCalculator::switchShowAccels, pbC5, &KCalcConstButton::slotSetAccelDisplayMode);
558     connect(this, &KCalculator::switchMode, pbC5, &KCalcConstButton::slotSetMode);
559     connect(pbC5, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
560 
561     pbC6->setButtonNumber(5);
562     connect(this, &KCalculator::switchShowAccels, pbC6, &KCalcConstButton::slotSetAccelDisplayMode);
563     connect(this, &KCalculator::switchMode, pbC6, &KCalcConstButton::slotSetMode);
564     connect(pbC6, &KCalcConstButton::constButtonClicked, this, &KCalculator::slotConstclicked);
565 
566     changeButtonNames();
567 }
568 
569 //------------------------------------------------------------------------------
570 // Name: setupMiscKeys
571 // Desc: sets up misc keys and related shortcuts
572 //------------------------------------------------------------------------------
setupMiscKeys()573 void KCalculator::setupMiscKeys()
574 {
575     pbMod->addMode(ModeNormal, i18nc("Modulo", "mod"), i18n("Modulo"));
576     pbMod->addMode(ModeShift, i18nc("Integer division", "IntDiv"), i18n("Integer division"));
577     connect(this, &KCalculator::switchMode, pbMod, &KCalcButton::slotSetMode);
578     connect(this, &KCalculator::switchShowAccels, pbMod, &KCalcButton::slotSetAccelDisplayMode);
579     pbMod->setShortcut(QKeySequence(Qt::Key_Colon));
580     connect(pbMod, &KCalcButton::clicked, this, &KCalculator::slotModclicked);
581 
582     pbReci->addMode(ModeNormal, i18nc("Reciprocal", "1/x"), i18n("Reciprocal"));
583     pbReci->addMode(ModeShift, i18nc("n Choose m", "nCm"), i18n("n Choose m"));
584     connect(this, &KCalculator::switchMode, pbReci, &KCalcButton::slotSetMode);
585     connect(this, &KCalculator::switchShowAccels, pbReci, &KCalcButton::slotSetAccelDisplayMode);
586     connect(pbReci, &KCalcButton::clicked, this, &KCalculator::slotReciclicked);
587 
588     pbFactorial->addMode(ModeNormal, i18nc("Factorial", "x!"), i18n("Factorial"));
589     pbFactorial->addMode(ModeShift, QStringLiteral("&#915;"), i18n("Gamma"));
590     pbFactorial->setShortcut(QKeySequence(Qt::Key_Exclam));
591     connect(this, &KCalculator::switchShowAccels, pbFactorial, &KCalcButton::slotSetAccelDisplayMode);
592     connect(this, &KCalculator::switchMode, pbFactorial, &KCalcButton::slotSetMode);
593     connect(pbFactorial, &KCalcButton::clicked, this, &KCalculator::slotFactorialclicked);
594 
595     pbSquare->addMode(ModeNormal, i18nc("Square", "x<sup>2</sup>"), i18n("Square"));
596     pbSquare->addMode(ModeShift, QStringLiteral("&radic;x"), i18n("Square root"));
597     pbSquare->setShortcut(QKeySequence(Qt::Key_BracketLeft));
598     new QShortcut(Qt::Key_twosuperior, pbSquare, SLOT(animateClick()));
599     connect(this, &KCalculator::switchShowAccels, pbSquare, &KCalcButton::slotSetAccelDisplayMode);
600     connect(this, &KCalculator::switchMode, pbSquare, &KCalcButton::slotSetMode);
601     connect(pbSquare, &KCalcButton::clicked, this, &KCalculator::slotSquareclicked);
602 
603     pbPower->addMode(ModeNormal, i18nc("x to the power of y", "x<sup>y</sup>"), i18n("x to the power of y"));
604     pbPower->addMode(ModeShift, i18nc("x to the power of 1/y", "x<sup>1/y</sup>"), i18n("x to the power of 1/y"));
605     connect(this, &KCalculator::switchShowAccels, pbPower, &KCalcButton::slotSetAccelDisplayMode);
606     connect(this, &KCalculator::switchMode, pbPower, &KCalcButton::slotSetMode);
607     pbPower->setShortcut(QKeySequence(Qt::Key_AsciiCircum));
608     connect(pbPower, &KCalcButton::clicked, this, &KCalculator::slotPowerclicked);
609 
610     pbEE->addMode(ModeNormal,
611                   QStringLiteral("x<small>"
612                                  "\xb7"
613                                  "10</small><sup>y</sup>"),
614                   i18n("Exponent"));
615     connect(this, &KCalculator::switchShowAccels, pbEE, &KCalcButton::slotSetAccelDisplayMode);
616     connect(pbEE, &KCalcButton::clicked, this, &KCalculator::slotEEclicked);
617 }
618 
619 //------------------------------------------------------------------------------
620 // Name: createConstantsMenu
621 // Desc: additional setup for button keys
622 // NOTE: all alphanumeric shorts set in ui file
623 //------------------------------------------------------------------------------
setupKeys()624 void KCalculator::setupKeys()
625 {
626     setupNumberKeys();
627     setupRightKeypad();
628     setupNumericKeypad();
629     setupLogicKeys();
630     setupScientificKeys();
631     setupStatisticKeys();
632     setupConstantsKeys();
633     setupMiscKeys();
634 
635     // other button lists
636 
637     function_button_list_.append(pbHyp);
638     function_button_list_.append(pbShift);
639     function_button_list_.append(pbEE);
640     function_button_list_.append(pbSin);
641     function_button_list_.append(pbPlusMinus);
642     function_button_list_.append(pbCos);
643     function_button_list_.append(pbReci);
644     function_button_list_.append(pbTan);
645     function_button_list_.append(pbFactorial);
646     function_button_list_.append(pbLog);
647     function_button_list_.append(pbSquare);
648     function_button_list_.append(pbLn);
649     function_button_list_.append(pbPower);
650     function_button_list_.append(pbCube);
651 
652     mem_button_list_.append(pbMemRecall);
653     mem_button_list_.append(pbMemPlusMinus);
654     mem_button_list_.append(pbMemStore);
655     mem_button_list_.append(pbMemClear);
656     mem_button_list_.append(pbClear);
657     mem_button_list_.append(pbAllClear);
658     mem_button_list_.append(pbBackspace);
659 
660     operation_button_list_.append(pbMultiplication);
661     operation_button_list_.append(pbParenOpen);
662     operation_button_list_.append(pbParenClose);
663     operation_button_list_.append(pbAND);
664     operation_button_list_.append(pbDivision);
665     operation_button_list_.append(pbOR);
666     operation_button_list_.append(pbXOR);
667     operation_button_list_.append(pbPlus);
668     operation_button_list_.append(pbMinus);
669     operation_button_list_.append(pbLsh);
670     operation_button_list_.append(pbRsh);
671     operation_button_list_.append(pbPeriod);
672     operation_button_list_.append(pbEqual);
673     operation_button_list_.append(pbPercent);
674     operation_button_list_.append(pbCmp);
675     operation_button_list_.append(pbMod);
676 }
677 
678 //------------------------------------------------------------------------------
679 // Name: updateGeometry
680 // Desc: makes all the buttons have reasonable sizes
681 //------------------------------------------------------------------------------
updateGeometry()682 void KCalculator::updateGeometry()
683 {
684     const QSize em = pbAND->fontMetrics().size(0, QStringLiteral("M"));
685     int margin = QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, nullptr);
686     margin = qMax(qMin(margin / 2, 3), 3);
687 
688     // left pad
689     const auto leftPadList = leftPad->children();
690     for (QObject *obj : leftPadList) {
691         if (auto const button = qobject_cast<KCalcButton *>(obj)) {
692             button->setFixedWidth(em.width() * 4 + margin * 2);
693             button->installEventFilter(this);
694         }
695     }
696 
697     // right pad
698     const auto rightPadList = rightPad->children();
699     for (QObject *obj : rightPadList) {
700         auto const button = qobject_cast<KCalcButton *>(obj);
701         // let Shift expand freely
702         if (button && button != pbShift) {
703             button->setFixedWidth(em.width() * 3 + margin * 2);
704             button->installEventFilter(this);
705         }
706     }
707 
708     // numeric pad
709     const auto numericPadList = numericPad->children();
710     for (QObject *obj : numericPadList) {
711         if (auto const button = qobject_cast<KCalcButton *>(obj)) {
712             // let pb0 expand freely
713             if (button != pb0) {
714                 button->setFixedWidth(em.width() * 3 + margin * 2);
715             }
716             button->installEventFilter(this);
717         }
718     }
719 }
720 
721 //------------------------------------------------------------------------------
722 // Name: slotConstantToDisplay
723 // Desc: inserts a constant
724 //------------------------------------------------------------------------------
slotConstantToDisplay(const science_constant & const_chosen)725 void KCalculator::slotConstantToDisplay(const science_constant &const_chosen)
726 {
727     QString val = const_chosen.value;
728     val.replace(QLatin1Char('.'), KNumber::decimalSeparator());
729     calc_display->setAmount(KNumber(val));
730     updateDisplay({});
731     core.setOnlyUpdateOperation(false);
732 }
733 
734 //------------------------------------------------------------------------------
735 // Name: slotBaseSelected
736 // Desc: changes the selected numeric base
737 //------------------------------------------------------------------------------
slotBaseSelected(QAbstractButton * button)738 void KCalculator::slotBaseSelected(QAbstractButton *button)
739 {
740     if (button) {
741         const int base = base_choose_group_->id(button);
742         int current_base;
743 
744         // set display & statusbar (if item exist in statusbar)
745         statusBar()->setBase(base);
746         switch (base) {
747         case BinMode:
748             current_base = calc_display->setBase(NumBase(2));
749             calc_display->setStatusText(BaseField, QStringLiteral("Bin"));
750             break;
751         case OctMode:
752             current_base = calc_display->setBase(NumBase(8));
753             calc_display->setStatusText(BaseField, QStringLiteral("Oct"));
754             break;
755         case DecMode:
756             current_base = calc_display->setBase(NumBase(10));
757             calc_display->setStatusText(BaseField, QStringLiteral("Dec"));
758             break;
759         case HexMode:
760             current_base = calc_display->setBase(NumBase(16));
761             calc_display->setStatusText(BaseField, QStringLiteral("Hex"));
762             break;
763         default:
764             calc_display->setStatusText(BaseField, QStringLiteral("Error"));
765             return;
766         }
767 
768         // Enable the buttons available in this base
769         for (int i = 0; i < current_base; ++i) {
770             (num_button_group_->buttons().at(i))->setEnabled(true);
771         }
772 
773         // Disable the buttons not available in this base
774         for (int i = current_base; i < 16; ++i) {
775             (num_button_group_->buttons().at(i))->setEnabled(false);
776         }
777 
778         // Only enable the decimal point in decimal
779         pbPeriod->setEnabled(current_base == NB_DECIMAL);
780 
781         // Only enable the x*10^y button in decimal
782         pbEE->setEnabled(current_base == NB_DECIMAL);
783 
784         // Disable buttons that make only sense with floating point numbers
785         if (current_base != NB_DECIMAL) {
786             for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
787                 btn->setEnabled(false);
788             }
789         } else {
790             for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
791                 btn->setEnabled(true);
792             }
793         }
794 
795         KCalcSettings::setBaseMode(base);
796     }
797 }
798 
799 //------------------------------------------------------------------------------
800 // Name: keyPressEvent
801 // Desc: handles keypress events
802 //------------------------------------------------------------------------------
keyPressEvent(QKeyEvent * e)803 void KCalculator::keyPressEvent(QKeyEvent *e)
804 {
805     // Fix for bug #314586
806     // Basically, on some keyboards such as French, even though the decimal separator
807     // is "," the numeric keypad has a "." key. So we fake it so people can more seamlessly
808     // enter numbers using the keypad
809     if (KNumber::decimalSeparator() != QLatin1String(".")) {
810         if (e->key() == Qt::Key_Period && e->modifiers() & Qt::KeypadModifier) {
811             pbPeriod->animateClick();
812         }
813     }
814 
815     if (((e->modifiers() & Qt::NoModifier) == 0) || (e->modifiers() & Qt::ShiftModifier)) {
816         switch (e->key()) {
817         case Qt::Key_Backspace:
818             calc_display->deleteLastDigit();
819             break;
820         }
821     }
822 
823     if (e->key() == Qt::Key_Control) {
824         Q_EMIT switchShowAccels(true);
825     }
826 
827     // Workaround for bug #283521
828     // Unfortunately adding multiple shortcuts (A, Shift+A) to pushbuttons
829     // does not work properly, so we handle the A-F keypresses with shift in Hex mode here
830     if (hexRadio->isChecked() && e->modifiers() & Qt::ShiftModifier) {
831         switch (e->key()) {
832         case Qt::Key_A:
833             pbA->animateClick();
834             break;
835         case Qt::Key_B:
836             pbB->animateClick();
837             break;
838         case Qt::Key_C:
839             pbC->animateClick();
840             break;
841         case Qt::Key_D:
842             pbD->animateClick();
843             break;
844         case Qt::Key_E:
845             pbE->animateClick();
846             break;
847         case Qt::Key_F:
848             pbF->animateClick();
849             break;
850         default:
851             break;
852         }
853     }
854 }
855 
856 //------------------------------------------------------------------------------
857 // Name: keyReleaseEvent
858 // Desc: handles keyrelease events
859 //------------------------------------------------------------------------------
keyReleaseEvent(QKeyEvent * e)860 void KCalculator::keyReleaseEvent(QKeyEvent *e)
861 {
862     if (e->key() == Qt::Key_Control) {
863         Q_EMIT switchShowAccels(false);
864     }
865 }
866 
867 //------------------------------------------------------------------------------
868 // Name: slotAngleSelected
869 // Desc: changes the selected angle system
870 //------------------------------------------------------------------------------
slotAngleSelected(QAbstractButton * button)871 void KCalculator::slotAngleSelected(QAbstractButton *button)
872 {
873     if (button) {
874         const int mode = angle_choose_group_->id(button);
875         angle_mode_ = mode;
876 
877         statusBar()->setAngleMode(KCalcStatusBar::AngleMode(mode));
878         switch (mode) {
879         case DegMode:
880             calc_display->setStatusText(AngleField, QStringLiteral("Deg"));
881             break;
882         case RadMode:
883             calc_display->setStatusText(AngleField, QStringLiteral("Rad"));
884             break;
885         case GradMode:
886             calc_display->setStatusText(AngleField, QStringLiteral("Gra"));
887             break;
888         default: // we shouldn't ever end up here
889             angle_mode_ = RadMode;
890         }
891 
892         KCalcSettings::setAngleMode(angle_mode_);
893     }
894 }
895 
896 //------------------------------------------------------------------------------
897 // Name: slotEEclicked
898 // Desc: starts the entering of numbers using scientific notation
899 //------------------------------------------------------------------------------
slotEEclicked()900 void KCalculator::slotEEclicked()
901 {
902     calc_display->newCharacter(QLatin1Char('e'));
903 }
904 
905 //------------------------------------------------------------------------------
906 // Name: slotShifttoggled
907 // Desc: updates the shift state for alternate button functionality
908 //------------------------------------------------------------------------------
slotShifttoggled(bool flag)909 void KCalculator::slotShifttoggled(bool flag)
910 {
911     shift_mode_ = flag;
912 
913     Q_EMIT switchMode(ModeShift, flag);
914 
915     statusBar()->setShiftIndicator(shift_mode_);
916     if (shift_mode_) {
917         calc_display->setStatusText(ShiftField, i18n("Shift"));
918     } else {
919         calc_display->setStatusText(ShiftField, QString());
920     }
921 }
922 
923 //------------------------------------------------------------------------------
924 // Name: slotHyptoggled
925 // Desc: updates the Hyp state for alternate trig button functionality
926 //------------------------------------------------------------------------------
slotHyptoggled(bool flag)927 void KCalculator::slotHyptoggled(bool flag)
928 {
929     // toggle between hyperbolic and standard trig functions
930     hyp_mode_ = flag;
931 
932     Q_EMIT switchMode(ModeHyperbolic, flag);
933 }
934 
935 //------------------------------------------------------------------------------
936 // Name: slotMemRecallclicked
937 // Desc: recalls a value from memory
938 //------------------------------------------------------------------------------
slotMemRecallclicked()939 void KCalculator::slotMemRecallclicked()
940 {
941     // temp. work-around
942     calc_display->sendEvent(KCalcDisplay::EventReset);
943 
944 	// temp. work-around
945 	calc_display->sendEvent(KCalcDisplay::EventReset);
946 
947     calc_history->addToHistory(QStringLiteral("MR"), false);
948 
949     calc_display->setAmount(memory_num_);
950     updateDisplay({});
951     core.setOnlyUpdateOperation(false);
952     calc_history->addResultToHistory(memory_num_.toQString());
953 }
954 
955 //------------------------------------------------------------------------------
956 // Name: slotMemStoreclicked
957 // Desc: stores a value into memory
958 //------------------------------------------------------------------------------
slotMemStoreclicked()959 void KCalculator::slotMemStoreclicked()
960 {
961     calc_history->addToHistory(QStringLiteral("M"), false);
962     update_history_window_ = false;
963     EnterEqual(CalcEngine::REPEAT_PREVENT);
964 
965     memory_num_ = calc_display->getAmount();
966     calc_display->setStatusText(MemField, QStringLiteral("M"));
967     statusBar()->setMemoryIndicator(true);
968     pbMemRecall->setEnabled(true);
969 }
970 
971 //------------------------------------------------------------------------------
972 // Name: slotNumberclicked
973 // Desc: user has entered a digit
974 //------------------------------------------------------------------------------
slotNumberclicked(QAbstractButton * button)975 void KCalculator::slotNumberclicked(QAbstractButton *button)
976 {
977     if (button) {
978         const int number_clicked = num_button_group_->id(button);
979         calc_display->enterDigit(number_clicked);
980         core.setOnlyUpdateOperation(false);
981     }
982 }
983 
984 //------------------------------------------------------------------------------
985 // Name: slotSinclicked
986 // Desc: executes the sine function
987 //------------------------------------------------------------------------------
slotSinclicked()988 void KCalculator::slotSinclicked()
989 {
990     if (hyp_mode_) {
991         // sinh or arsinh
992         if (!shift_mode_) {
993             calc_history->addFuncToHistory(QStringLiteral("sinh"));
994             core.SinHyp(calc_display->getAmount());
995         } else {
996             calc_history->addFuncToHistory(QStringLiteral("arcsinh"));
997             core.AreaSinHyp(calc_display->getAmount());
998         }
999     } else {
1000         // sine or arcsine
1001         if (!shift_mode_) {
1002             calc_history->addFuncToHistory(QStringLiteral("sin"));
1003             switch (angle_mode_) {
1004             case DegMode:
1005                 core.SinDeg(calc_display->getAmount());
1006                 break;
1007             case RadMode:
1008                 core.SinRad(calc_display->getAmount());
1009                 break;
1010             case GradMode:
1011                 core.SinGrad(calc_display->getAmount());
1012                 break;
1013             }
1014         } else {
1015             calc_history->addFuncToHistory(QStringLiteral("arcsin"));
1016             switch (angle_mode_) {
1017             case DegMode:
1018                 core.ArcSinDeg(calc_display->getAmount());
1019                 break;
1020             case RadMode:
1021                 core.ArcSinRad(calc_display->getAmount());
1022                 break;
1023             case GradMode:
1024                 core.ArcSinGrad(calc_display->getAmount());
1025                 break;
1026             }
1027         }
1028     }
1029 
1030     updateDisplay(UPDATE_FROM_CORE);
1031     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1032 }
1033 
1034 //------------------------------------------------------------------------------
1035 // Name: slotPlusMinusclicked
1036 // Desc: changes sign of number being displayed
1037 //------------------------------------------------------------------------------
slotPlusMinusclicked()1038 void KCalculator::slotPlusMinusclicked()
1039 {
1040     // display can only change sign, when in input mode, otherwise we
1041     // need the core to do this.
1042     if (!calc_display->sendEvent(KCalcDisplay::EventChangeSign)) {
1043         core.InvertSign(calc_display->getAmount());
1044         update_history_window_ = false;
1045         updateDisplay(UPDATE_FROM_CORE);
1046     }
1047 }
1048 
1049 //------------------------------------------------------------------------------
1050 // Name: slotMemPlusMinusclicked
1051 // Desc: handles arithmetic on values stored in memory
1052 //------------------------------------------------------------------------------
slotMemPlusMinusclicked()1053 void KCalculator::slotMemPlusMinusclicked()
1054 {
1055     bool tmp_shift_mode = shift_mode_; // store this, because next command deletes shift_mode_
1056     update_history_window_ = false;
1057     if (!tmp_shift_mode) {
1058         calc_history->addToHistory(QStringLiteral("M+"), false);
1059     } else {
1060         calc_history->addToHistory(QStringLiteral("M-"), false);
1061     }
1062 
1063     EnterEqual(); // finish calculation so far, to store result into MEM
1064 
1065     if (!tmp_shift_mode) {
1066         memory_num_ += calc_display->getAmount();
1067     } else {
1068         memory_num_ -= calc_display->getAmount();
1069     }
1070 
1071     pbShift->setChecked(false);
1072     statusBar()->setMemoryIndicator(true);
1073     calc_display->setStatusText(MemField, i18n("M"));
1074     pbMemRecall->setEnabled(true);
1075 }
1076 
1077 //------------------------------------------------------------------------------
1078 // Name: slotSinclicked
1079 // Desc: executes the cosine function
1080 //------------------------------------------------------------------------------
slotCosclicked()1081 void KCalculator::slotCosclicked()
1082 {
1083     if (hyp_mode_) {
1084         // cosh or arcosh
1085         if (!shift_mode_) {
1086             calc_history->addFuncToHistory(QStringLiteral("cosh"));
1087             core.CosHyp(calc_display->getAmount());
1088         } else {
1089             calc_history->addFuncToHistory(QStringLiteral("arcosh"));
1090             core.AreaCosHyp(calc_display->getAmount());
1091         }
1092     } else {
1093         // cosine or arccosine
1094         if (!shift_mode_) {
1095             calc_history->addFuncToHistory(QStringLiteral("cos"));
1096             switch (angle_mode_) {
1097             case DegMode:
1098                 core.CosDeg(calc_display->getAmount());
1099                 break;
1100             case RadMode:
1101                 core.CosRad(calc_display->getAmount());
1102                 break;
1103             case GradMode:
1104                 core.CosGrad(calc_display->getAmount());
1105                 break;
1106             }
1107         } else {
1108             calc_history->addFuncToHistory(QStringLiteral("arccos"));
1109             switch (angle_mode_) {
1110             case DegMode:
1111                 core.ArcCosDeg(calc_display->getAmount());
1112                 break;
1113             case RadMode:
1114                 core.ArcCosRad(calc_display->getAmount());
1115                 break;
1116             case GradMode:
1117                 core.ArcCosGrad(calc_display->getAmount());
1118                 break;
1119             }
1120         }
1121     }
1122 
1123     updateDisplay(UPDATE_FROM_CORE);
1124     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1125 }
1126 
1127 //------------------------------------------------------------------------------
1128 // Name: slotSinclicked
1129 // Desc: executes the reciprocal function
1130 //------------------------------------------------------------------------------
slotReciclicked()1131 void KCalculator::slotReciclicked()
1132 {
1133     if (shift_mode_) {
1134         calc_history->addFuncToHistory(QStringLiteral("nCm"));
1135         core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_BINOM);
1136     } else {
1137         calc_history->addFuncToHistory(QStringLiteral("1/"));
1138         core.Reciprocal(calc_display->getAmount());
1139         updateDisplay(UPDATE_FROM_CORE);
1140         calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1141         return;
1142     }
1143 
1144     // temp. work-around
1145     KNumber tmp_num = calc_display->getAmount();
1146     calc_display->sendEvent(KCalcDisplay::EventReset);
1147     calc_display->setAmount(tmp_num);
1148     updateDisplay({});
1149     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1150     if (shift_mode_) {
1151         updateHistoryWithFunction(CalcEngine::FUNC_BINOM);
1152     }
1153 }
1154 
1155 //------------------------------------------------------------------------------
1156 // Name: slotSinclicked
1157 // Desc: executes the tangent function
1158 //------------------------------------------------------------------------------
slotTanclicked()1159 void KCalculator::slotTanclicked()
1160 {
1161     if (hyp_mode_) {
1162         // tanh or artanh
1163         if (!shift_mode_) {
1164             calc_history->addFuncToHistory(QStringLiteral("tanh"));
1165             core.TangensHyp(calc_display->getAmount());
1166         } else {
1167             calc_history->addFuncToHistory(QStringLiteral("artanh"));
1168             core.AreaTangensHyp(calc_display->getAmount());
1169         }
1170     } else {
1171         // tan or arctan
1172         if (!shift_mode_) {
1173             calc_history->addFuncToHistory(QStringLiteral("tan"));
1174             switch (angle_mode_) {
1175             case DegMode:
1176                 core.TangensDeg(calc_display->getAmount());
1177                 break;
1178             case RadMode:
1179                 core.TangensRad(calc_display->getAmount());
1180                 break;
1181             case GradMode:
1182                 core.TangensGrad(calc_display->getAmount());
1183                 break;
1184             }
1185         } else {
1186             calc_history->addFuncToHistory(QStringLiteral("arctan"));
1187             switch (angle_mode_) {
1188             case DegMode:
1189                 core.ArcTangensDeg(calc_display->getAmount());
1190                 break;
1191             case RadMode:
1192                 core.ArcTangensRad(calc_display->getAmount());
1193                 break;
1194             case GradMode:
1195                 core.ArcTangensGrad(calc_display->getAmount());
1196                 break;
1197             }
1198         }
1199     }
1200 
1201     updateDisplay(UPDATE_FROM_CORE);
1202     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1203 }
1204 
1205 //------------------------------------------------------------------------------
1206 // Name: slotFactorialclicked
1207 // Desc: executes the factorial function
1208 //------------------------------------------------------------------------------
slotFactorialclicked()1209 void KCalculator::slotFactorialclicked()
1210 {
1211     bool gamma_ = false;
1212     // Set WaitCursor, as this operation may take looooong
1213     // time and UI frezes with large numbers. User needs some
1214     // visual feedback.
1215     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1216     if (!shift_mode_) {
1217         core.Factorial(calc_display->getAmount());
1218     } else {
1219         core.Gamma(calc_display->getAmount());
1220         gamma_ = true;
1221     }
1222     QApplication::restoreOverrideCursor();
1223     updateDisplay(UPDATE_FROM_CORE);
1224     if (gamma_) {
1225         calc_history->addFuncToHistory(QStringLiteral("&#915;"));
1226     } else {
1227         calc_history->addFuncToHistory(QStringLiteral("!"));
1228     }
1229     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1230 }
1231 
1232 //------------------------------------------------------------------------------
1233 // Name: slotLogclicked
1234 // Desc: executes the Log function
1235 //------------------------------------------------------------------------------
slotLogclicked()1236 void KCalculator::slotLogclicked()
1237 {
1238     if (!shift_mode_) {
1239         core.Log10(calc_display->getAmount());
1240         calc_history->addFuncToHistory(QStringLiteral("log"));
1241     } else {
1242         update_history_window_ = false;
1243         core.Exp10(calc_display->getAmount());
1244         calc_history->addFuncToHistory(QStringLiteral("10<sup>") + calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("</sup>"));
1245     }
1246 
1247     updateDisplay(UPDATE_FROM_CORE);
1248     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1249 }
1250 
1251 //------------------------------------------------------------------------------
1252 // Name: slotSquareclicked
1253 // Desc: executes the x^2 function
1254 //------------------------------------------------------------------------------
slotSquareclicked()1255 void KCalculator::slotSquareclicked()
1256 {
1257     bool tmp_shift_mode = shift_mode_;
1258     if (!shift_mode_) {
1259         core.Square(calc_display->getAmount());
1260     } else {
1261         calc_history->addFuncToHistory(QStringLiteral("&radic;"));
1262         core.SquareRoot(calc_display->getAmount());
1263     }
1264 
1265     updateDisplay(UPDATE_FROM_CORE);
1266     if (!tmp_shift_mode) {
1267         calc_history->addFuncToHistory(QStringLiteral("<sup>2</sup>"));
1268     }
1269     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1270 }
1271 
1272 //------------------------------------------------------------------------------
1273 // Name: slotCubeclicked
1274 // Desc: executes the x^3 function
1275 //------------------------------------------------------------------------------
slotCubeclicked()1276 void KCalculator::slotCubeclicked()
1277 {
1278     bool tmp_shift_mode = shift_mode_;
1279     if (!shift_mode_) {
1280         core.Cube(calc_display->getAmount());
1281     } else {
1282         calc_history->addFuncToHistory(QStringLiteral("<sup>3</sup>&radic;"));
1283         core.CubeRoot(calc_display->getAmount());
1284     }
1285 
1286     updateDisplay(UPDATE_FROM_CORE);
1287     if (!tmp_shift_mode) {
1288         calc_history->addFuncToHistory(QStringLiteral("<sup>3</sup>"));
1289     }
1290     calc_history->addResultToHistory(calc_display->formatDecimalNumber(calc_display->getAmount().toQString(KCalcSettings::precision())));
1291 }
1292 
1293 //------------------------------------------------------------------------------
1294 // Name: slotCubeclicked
1295 // Desc: executes the ln function
1296 //------------------------------------------------------------------------------
slotLnclicked()1297 void KCalculator::slotLnclicked()
1298 {
1299     if (!shift_mode_) {
1300         calc_history->addFuncToHistory(QStringLiteral("ln"));
1301         core.Ln(calc_display->getAmount());
1302     } else {
1303         calc_history->addFuncToHistory(QStringLiteral("e<sup>") + calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("</sup>"));
1304         core.Exp(calc_display->getAmount());
1305     }
1306 
1307     updateDisplay(UPDATE_FROM_CORE);
1308     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1309 }
1310 
1311 //------------------------------------------------------------------------------
1312 // Name: slotPowerclicked
1313 // Desc: executes the x^y function
1314 //------------------------------------------------------------------------------
slotPowerclicked()1315 void KCalculator::slotPowerclicked()
1316 {
1317     if (shift_mode_) {
1318         calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()) + QStringLiteral("&nbsp;^ 1/"), false);
1319         core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PWR_ROOT);
1320         pbShift->setChecked(false);
1321     } else {
1322         calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()), false);
1323         calc_history->addFuncToHistory(QStringLiteral("^"));
1324         core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_POWER);
1325     }
1326 
1327     // temp. work-around
1328     KNumber tmp_num = calc_display->getAmount();
1329     calc_display->sendEvent(KCalcDisplay::EventReset);
1330     calc_display->setAmount(tmp_num);
1331     updateDisplay({});
1332 }
1333 
1334 //------------------------------------------------------------------------------
1335 // Name: slotMemClearclicked
1336 // Desc: executes the MC function
1337 //------------------------------------------------------------------------------
slotMemClearclicked()1338 void KCalculator::slotMemClearclicked()
1339 {
1340     memory_num_ = KNumber::Zero;
1341     statusBar()->setMemoryIndicator(false);
1342     calc_display->setStatusText(MemField, QString());
1343     pbMemRecall->setDisabled(true);
1344     calc_history->addToHistory(QStringLiteral("M cleared"), true);
1345 }
1346 
1347 //------------------------------------------------------------------------------
1348 // Name: slotBackspaceclicked
1349 // Desc: removes the last input digit
1350 //------------------------------------------------------------------------------
slotBackspaceclicked()1351 void KCalculator::slotBackspaceclicked()
1352 {
1353     calc_display->deleteLastDigit();
1354 }
1355 
1356 //------------------------------------------------------------------------------
1357 // Name: slotClearclicked
1358 // Desc: clears the display
1359 //------------------------------------------------------------------------------
slotClearclicked()1360 void KCalculator::slotClearclicked()
1361 {
1362     calc_display->sendEvent(KCalcDisplay::EventClear);
1363 }
1364 
1365 //------------------------------------------------------------------------------
1366 // Name: slotAllClearclicked
1367 // Desc: clears everything
1368 //------------------------------------------------------------------------------
slotAllClearclicked()1369 void KCalculator::slotAllClearclicked()
1370 {
1371     core.Reset();
1372     calc_display->sendEvent(KCalcDisplay::EventReset);
1373     updateDisplay(UPDATE_FROM_CORE);
1374 }
1375 
1376 //------------------------------------------------------------------------------
1377 // Name: slotParenOpenclicked
1378 // Desc: starts a sub-expression
1379 //------------------------------------------------------------------------------
slotParenOpenclicked()1380 void KCalculator::slotParenOpenclicked()
1381 {
1382     core.ParenOpen(calc_display->getAmount());
1383     calc_history->addFuncToHistory(QStringLiteral("("));
1384 }
1385 
1386 //------------------------------------------------------------------------------
1387 // Name: slotParenCloseclicked
1388 // Desc: ends a sub-expression
1389 //------------------------------------------------------------------------------
slotParenCloseclicked()1390 void KCalculator::slotParenCloseclicked()
1391 {
1392     core.ParenClose(calc_display->getAmount());
1393     updateDisplay(UPDATE_FROM_CORE);
1394     calc_history->addFuncToHistory(QStringLiteral(")"));
1395     update_history_window_ = false;
1396 }
1397 
1398 //------------------------------------------------------------------------------
1399 // Name: slotANDclicked
1400 // Desc: executes a bitwise AND
1401 //------------------------------------------------------------------------------
slotANDclicked()1402 void KCalculator::slotANDclicked()
1403 {
1404     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_AND);
1405     updateDisplay(UPDATE_FROM_CORE);
1406     updateHistoryWithFunction(CalcEngine::FUNC_AND);
1407 }
1408 
1409 //------------------------------------------------------------------------------
1410 // Name: slotMultiplicationclicked
1411 // Desc: executes multiplication
1412 //------------------------------------------------------------------------------
slotMultiplicationclicked()1413 void KCalculator::slotMultiplicationclicked()
1414 {
1415     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MULTIPLY);
1416     updateDisplay(UPDATE_FROM_CORE);
1417     updateHistoryWithFunction(CalcEngine::FUNC_MULTIPLY);
1418 }
1419 
1420 //------------------------------------------------------------------------------
1421 // Name: slotDivisionclicked
1422 // Desc: executes division
1423 //------------------------------------------------------------------------------
slotDivisionclicked()1424 void KCalculator::slotDivisionclicked()
1425 {
1426     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_DIVIDE);
1427     updateDisplay(UPDATE_FROM_CORE);
1428     updateHistoryWithFunction(CalcEngine::FUNC_DIVIDE);
1429 }
1430 
1431 //------------------------------------------------------------------------------
1432 // Name: slotORclicked
1433 // Desc: executes a bitwise OR
1434 //------------------------------------------------------------------------------
slotORclicked()1435 void KCalculator::slotORclicked()
1436 {
1437     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_OR);
1438     updateDisplay(UPDATE_FROM_CORE);
1439     updateHistoryWithFunction(CalcEngine::FUNC_OR);
1440 }
1441 
1442 //------------------------------------------------------------------------------
1443 // Name: slotXORclicked
1444 // Desc: executes a bitwise XOR
1445 //------------------------------------------------------------------------------
slotXORclicked()1446 void KCalculator::slotXORclicked()
1447 {
1448     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_XOR);
1449     updateDisplay(UPDATE_FROM_CORE);
1450     updateHistoryWithFunction(CalcEngine::FUNC_XOR);
1451 }
1452 
1453 //------------------------------------------------------------------------------
1454 // Name: slotPlusclicked
1455 // Desc: executes addition
1456 //------------------------------------------------------------------------------
slotPlusclicked()1457 void KCalculator::slotPlusclicked()
1458 {
1459     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_ADD);
1460     updateDisplay(UPDATE_FROM_CORE);
1461     updateHistoryWithFunction(CalcEngine::FUNC_ADD);
1462 }
1463 
1464 //------------------------------------------------------------------------------
1465 // Name: slotPlusclicked
1466 // Desc: executes subtraction
1467 //------------------------------------------------------------------------------
slotMinusclicked()1468 void KCalculator::slotMinusclicked()
1469 {
1470     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_SUBTRACT);
1471     updateDisplay(UPDATE_FROM_CORE);
1472     updateHistoryWithFunction(CalcEngine::FUNC_SUBTRACT);
1473 }
1474 
1475 //------------------------------------------------------------------------------
1476 // Name: slotLeftShiftclicked
1477 // Desc: executes a bitwise left shift
1478 //------------------------------------------------------------------------------
slotLeftShiftclicked()1479 void KCalculator::slotLeftShiftclicked()
1480 {
1481     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_LSH);
1482     updateDisplay(UPDATE_FROM_CORE);
1483     updateHistoryWithFunction(CalcEngine::FUNC_LSH);
1484 }
1485 
1486 //------------------------------------------------------------------------------
1487 // Name: slotLeftShiftclicked
1488 // Desc: executes a bitwise right shift
1489 //------------------------------------------------------------------------------
slotRightShiftclicked()1490 void KCalculator::slotRightShiftclicked()
1491 {
1492     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_RSH);
1493     updateDisplay(UPDATE_FROM_CORE);
1494     updateHistoryWithFunction(CalcEngine::FUNC_RSH);
1495 }
1496 
1497 //------------------------------------------------------------------------------
1498 // Name: slotPeriodclicked
1499 // Desc: enters a decimal into the input stream
1500 //------------------------------------------------------------------------------
slotPeriodclicked()1501 void KCalculator::slotPeriodclicked()
1502 {
1503     // i know this isn't locale friendly, should be converted to appropriate
1504     // value at lower levels
1505     calc_display->newCharacter(QLocale().decimalPoint());
1506 }
1507 
1508 //------------------------------------------------------------------------------
1509 // Name: EnterEqual
1510 // Desc: calculates and displays the result of the pending operations
1511 //------------------------------------------------------------------------------
EnterEqual(CalcEngine::Repeat allow_repeat)1512 void KCalculator::EnterEqual(CalcEngine::Repeat allow_repeat)
1513 {
1514     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_EQUAL, allow_repeat);
1515     updateDisplay(UPDATE_FROM_CORE | UPDATE_STORE_RESULT);
1516     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1517 }
1518 
1519 //------------------------------------------------------------------------------
1520 // Name: slotEqualclicked
1521 // Desc: calculates and displays the result of the pending operations
1522 //------------------------------------------------------------------------------
slotEqualclicked()1523 void KCalculator::slotEqualclicked()
1524 {
1525     EnterEqual();
1526 }
1527 
1528 //------------------------------------------------------------------------------
1529 // Name: slotPercentclicked
1530 // Desc: calculates and displays the result of the pending operations as a percent
1531 //------------------------------------------------------------------------------
slotPercentclicked()1532 void KCalculator::slotPercentclicked()
1533 {
1534     core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PERCENT);
1535     updateDisplay(UPDATE_FROM_CORE);
1536     updateHistoryWithFunction(CalcEngine::FUNC_PERCENT);
1537     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1538 }
1539 
1540 //------------------------------------------------------------------------------
1541 // Name: slotNegateclicked
1542 // Desc: executes a bitwise 2's compliment
1543 // NOTE: implicitly converts the value to an unsigned quantity
1544 //------------------------------------------------------------------------------
slotNegateclicked()1545 void KCalculator::slotNegateclicked()
1546 {
1547     calc_history->addFuncToHistory(QStringLiteral("~"));
1548     core.Complement(calc_display->getAmount());
1549     updateDisplay(UPDATE_FROM_CORE);
1550     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1551 }
1552 
1553 //------------------------------------------------------------------------------
1554 // Name: slotModclicked
1555 // Desc: executes modulous (remainder division)
1556 //------------------------------------------------------------------------------
slotModclicked()1557 void KCalculator::slotModclicked()
1558 {
1559     if (shift_mode_) {
1560         core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_INTDIV);
1561     } else {
1562         core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MOD);
1563     }
1564 
1565     updateDisplay(UPDATE_FROM_CORE);
1566 
1567     if (shift_mode_) {
1568         updateHistoryWithFunction(CalcEngine::FUNC_INTDIV);
1569     } else {
1570         updateHistoryWithFunction(CalcEngine::FUNC_MOD);
1571     }
1572 }
1573 
1574 //------------------------------------------------------------------------------
1575 // Name: slotStatNumclicked
1576 // Desc: executes Sum function
1577 //------------------------------------------------------------------------------
slotStatNumclicked()1578 void KCalculator::slotStatNumclicked()
1579 {
1580     update_history_window_ = false;
1581     if (!shift_mode_) {
1582         core.StatCount(KNumber::Zero);
1583         calc_history->addToHistory(i18n("Number of data entered"), false);
1584     } else {
1585         pbShift->setChecked(false);
1586         core.StatSum(KNumber::Zero);
1587         calc_history->addToHistory(QString::fromUtf8("\xce\xa3") + QLatin1Char('x'), false);
1588     }
1589 
1590     updateDisplay(UPDATE_FROM_CORE);
1591     core.setOnlyUpdateOperation(false);
1592     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1593 }
1594 
1595 //------------------------------------------------------------------------------
1596 // Name: slotStatMeanclicked
1597 // Desc: executes Mean function
1598 //------------------------------------------------------------------------------
slotStatMeanclicked()1599 void KCalculator::slotStatMeanclicked()
1600 {
1601     update_history_window_ = false;
1602     if (!shift_mode_) {
1603         core.StatMean(KNumber::Zero);
1604         calc_history->addToHistory(i18n("Mean"), false);
1605     } else {
1606         pbShift->setChecked(false);
1607         core.StatSumSquares(KNumber::Zero);
1608         calc_history->addToHistory(QString::fromUtf8("\xce\xa3") + QStringLiteral("x<sup>2</sup>"), false);
1609     }
1610 
1611     updateDisplay(UPDATE_FROM_CORE);
1612     core.setOnlyUpdateOperation(false);
1613     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1614 }
1615 
1616 //------------------------------------------------------------------------------
1617 // Name: slotStatStdDevclicked
1618 // Desc: executes STD function
1619 //------------------------------------------------------------------------------
slotStatStdDevclicked()1620 void KCalculator::slotStatStdDevclicked()
1621 {
1622     update_history_window_ = false;
1623     if (shift_mode_) {
1624         // std (n-1)
1625         core.StatStdSample(KNumber::Zero);
1626         pbShift->setChecked(false);
1627         calc_history->addToHistory(QString::fromUtf8("\xcf\x83") + QStringLiteral("<sub>N-1</sub>"), false);
1628     } else {
1629         // std (n)
1630         core.StatStdDeviation(KNumber::Zero);
1631         calc_history->addToHistory(QString::fromUtf8("\xcf\x83") + QStringLiteral("N"), false);
1632     }
1633 
1634     updateDisplay(UPDATE_FROM_CORE);
1635     core.setOnlyUpdateOperation(false);
1636     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1637 }
1638 
1639 //------------------------------------------------------------------------------
1640 // Name: slotStatMedianclicked
1641 // Desc: executes Median function
1642 //------------------------------------------------------------------------------
slotStatMedianclicked()1643 void KCalculator::slotStatMedianclicked()
1644 {
1645     update_history_window_ = false;
1646     if (!shift_mode_) {
1647         core.StatMedian(KNumber::Zero);
1648     } else {
1649         core.StatMedian(KNumber::Zero);
1650         pbShift->setChecked(false);
1651     }
1652 
1653     calc_history->addToHistory(i18n("Median"), false);
1654     // TODO: it seems two different modes should be implemented, but...?
1655     updateDisplay(UPDATE_FROM_CORE);
1656     core.setOnlyUpdateOperation(false);
1657     calc_history->addResultToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()));
1658 }
1659 
1660 //------------------------------------------------------------------------------
1661 // Name: slotStatDataInputclicked
1662 // Desc: enters a value for statistical functions
1663 //------------------------------------------------------------------------------
slotStatDataInputclicked()1664 void KCalculator::slotStatDataInputclicked()
1665 {
1666     update_history_window_ = false;
1667     if (!shift_mode_) {
1668         bool tmp_error;
1669         core.StatDataNew(calc_display->getAmount());
1670         calc_history->addToHistory(i18n("DAT [") + core.lastOutput(tmp_error).toQString() + i18n("] = ")
1671                                        + calc_display->getAmount().toQString(KCalcSettings::precision()),
1672                                    true);
1673     } else {
1674         pbShift->setChecked(false);
1675         core.StatDataDel(KNumber::Zero);
1676         statusBar()->showMessage(i18n("Last stat item erased"), 3000);
1677         calc_history->addToHistory(i18n("Last stat item erased"), true);
1678     }
1679 
1680     updateDisplay(UPDATE_FROM_CORE);
1681     core.setOnlyUpdateOperation(false);
1682 }
1683 
1684 //------------------------------------------------------------------------------
1685 // Name: slotStatClearDataclicked
1686 // Desc: clears memory for statical functions
1687 //------------------------------------------------------------------------------
slotStatClearDataclicked()1688 void KCalculator::slotStatClearDataclicked()
1689 {
1690     if (!shift_mode_) {
1691         core.StatClearAll(KNumber::Zero);
1692         statusBar()->showMessage(i18n("Stat mem cleared"), 3000);
1693         calc_history->addToHistory(i18n("Stat mem cleared"), true);
1694     } else {
1695         pbShift->setChecked(false);
1696         updateDisplay({});
1697     }
1698 }
1699 
1700 //------------------------------------------------------------------------------
1701 // Name: slotConstclicked
1702 // Desc: enters a constant
1703 //------------------------------------------------------------------------------
slotConstclicked(int button)1704 void KCalculator::slotConstclicked(int button)
1705 {
1706     if (auto btn = qobject_cast<KCalcConstButton *>(const_buttons_[button])) {
1707         if (!shift_mode_) {
1708             // set the display to the configured value of constant button
1709             // internally, we deal with C locale style numbers, we need to convert
1710             QString val = btn->constant();
1711             val.replace(QLatin1Char('.'), KNumber::decimalSeparator());
1712             calc_display->setAmount(KNumber(val));
1713 
1714         } else {
1715             pbShift->setChecked(false);
1716 
1717             // internally, we deal with C locale style numbers, we need to convert
1718             QString val = calc_display->text();
1719             val.replace(KNumber::decimalSeparator(), QLatin1String("."));
1720             KCalcSettings::setValueConstant(button, val);
1721 
1722             // below set new tooltip
1723             btn->setLabelAndTooltip();
1724 
1725             // work around: after storing a number, pressing a digit should start
1726             // a new number
1727             calc_display->setAmount(calc_display->getAmount());
1728         }
1729 
1730         updateDisplay({});
1731         core.setOnlyUpdateOperation(false);
1732     }
1733 }
1734 
1735 //------------------------------------------------------------------------------
1736 // Name: showSettings
1737 // Desc: opens the shows the settings dialog
1738 //------------------------------------------------------------------------------
showSettings()1739 void KCalculator::showSettings()
1740 {
1741     // Check if there is already a dialog and if so bring
1742     // it to the foreground.
1743     if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
1744         return;
1745     }
1746 
1747     // Create a new dialog with the same name as the above checking code.
1748     auto const dialog = new KConfigDialog(this, QStringLiteral("settings"), KCalcSettings::self());
1749 
1750     // general settings
1751     auto const general = new General(nullptr);
1752     general->kcfg_Precision->setMaximum(maxprecision);
1753     dialog->addPage(general, i18n("General"), QStringLiteral("accessories-calculator"), i18n("General Settings"));
1754 
1755     // font settings
1756     auto const fonts = new Fonts(nullptr);
1757     dialog->addPage(fonts, i18n("Font"), QStringLiteral("preferences-desktop-font"), i18n("Select Display Font"));
1758 
1759     // color settings
1760     auto const color = new Colors(nullptr);
1761     dialog->addPage(color, i18n("Colors"), QStringLiteral("preferences-desktop-color"), i18n("Button & Display Colors"));
1762 
1763     // constant settings
1764     if (!constants_) {
1765         constants_ = new Constants(nullptr);
1766 
1767         KCalcConstMenu *tmp_menu;
1768         tmp_menu = new KCalcConstMenu(constants_);
1769         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst0);
1770         constants_->pushButton0->setMenu(tmp_menu);
1771 
1772         tmp_menu = new KCalcConstMenu(constants_);
1773         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst1);
1774         constants_->pushButton1->setMenu(tmp_menu);
1775 
1776         tmp_menu = new KCalcConstMenu(constants_);
1777         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst2);
1778         constants_->pushButton2->setMenu(tmp_menu);
1779 
1780         tmp_menu = new KCalcConstMenu(constants_);
1781         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst3);
1782         constants_->pushButton3->setMenu(tmp_menu);
1783 
1784         tmp_menu = new KCalcConstMenu(constants_);
1785         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst4);
1786         constants_->pushButton4->setMenu(tmp_menu);
1787 
1788         tmp_menu = new KCalcConstMenu(constants_);
1789         connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst5);
1790         constants_->pushButton5->setMenu(tmp_menu);
1791     }
1792 
1793     dialog->addPage(constants_, i18n("Constants"), QStringLiteral("preferences-kcalc-constants"), i18n("Define Constants"));
1794 
1795     // When the user clicks OK or Apply we want to update our settings.
1796     connect(dialog, &KConfigDialog::settingsChanged, this, &KCalculator::updateSettings);
1797 
1798     // Display the dialog.
1799     dialog->show();
1800 }
1801 
1802 // these 6 slots are just a quick hack, instead of setting the
1803 // TextEdit fields in the configuration dialog, we are setting the
1804 // Settingvalues themselves!!
1805 
1806 //------------------------------------------------------------------------------
1807 // Name: slotChooseScientificConst0
1808 // Desc: updates constants value
1809 //------------------------------------------------------------------------------
slotChooseScientificConst0(const science_constant & chosen_const)1810 void KCalculator::slotChooseScientificConst0(const science_constant &chosen_const)
1811 {
1812     constants_->kcfg_valueConstant0->setText(chosen_const.value);
1813     constants_->kcfg_nameConstant0->setText(chosen_const.label);
1814 }
1815 
1816 //------------------------------------------------------------------------------
1817 // Name: slotChooseScientificConst1
1818 // Desc: updates constants value
1819 //------------------------------------------------------------------------------
slotChooseScientificConst1(const science_constant & chosen_const)1820 void KCalculator::slotChooseScientificConst1(const science_constant &chosen_const)
1821 {
1822     constants_->kcfg_valueConstant1->setText(chosen_const.value);
1823     constants_->kcfg_nameConstant1->setText(chosen_const.label);
1824 }
1825 
1826 //------------------------------------------------------------------------------
1827 // Name: slotChooseScientificConst2
1828 // Desc: updates constants value
1829 //------------------------------------------------------------------------------
slotChooseScientificConst2(const science_constant & chosen_const)1830 void KCalculator::slotChooseScientificConst2(const science_constant &chosen_const)
1831 {
1832     constants_->kcfg_valueConstant2->setText(chosen_const.value);
1833     constants_->kcfg_nameConstant2->setText(chosen_const.label);
1834 }
1835 
1836 //------------------------------------------------------------------------------
1837 // Name: slotChooseScientificConst3
1838 // Desc: updates constants value
1839 //------------------------------------------------------------------------------
slotChooseScientificConst3(const science_constant & chosen_const)1840 void KCalculator::slotChooseScientificConst3(const science_constant &chosen_const)
1841 {
1842     constants_->kcfg_valueConstant3->setText(chosen_const.value);
1843     constants_->kcfg_nameConstant3->setText(chosen_const.label);
1844 }
1845 
1846 //------------------------------------------------------------------------------
1847 // Name: slotChooseScientificConst4
1848 // Desc: updates constants value
1849 //------------------------------------------------------------------------------
slotChooseScientificConst4(const science_constant & chosen_const)1850 void KCalculator::slotChooseScientificConst4(const science_constant &chosen_const)
1851 {
1852     constants_->kcfg_valueConstant4->setText(chosen_const.value);
1853     constants_->kcfg_nameConstant4->setText(chosen_const.label);
1854 }
1855 
1856 //------------------------------------------------------------------------------
1857 // Name: slotChooseScientificConst5
1858 // Desc: updates constants value
1859 //------------------------------------------------------------------------------
slotChooseScientificConst5(const science_constant & chosen_const)1860 void KCalculator::slotChooseScientificConst5(const science_constant &chosen_const)
1861 {
1862     constants_->kcfg_valueConstant5->setText(chosen_const.value);
1863     constants_->kcfg_nameConstant5->setText(chosen_const.label);
1864 }
1865 
1866 //------------------------------------------------------------------------------
1867 // Name: slotSetSimpleMode
1868 // Desc: sets the calculator to have a simple layout
1869 //------------------------------------------------------------------------------
slotSetSimpleMode()1870 void KCalculator::slotSetSimpleMode()
1871 {
1872     action_constants_show_->setChecked(false);
1873     action_constants_show_->setEnabled(false);
1874     action_bitset_show_->setEnabled(false);
1875     action_history_show_->setChecked(KCalcSettings::showHistory());
1876     showMemButtons(false);
1877     showScienceButtons(false);
1878     showStatButtons(false);
1879     showLogicButtons(false);
1880 
1881     // hide some individual buttons, which are not in one of the above groups
1882     pbShift->hide();
1883     pbMod->hide();
1884     pbReci->hide();
1885     pbFactorial->hide();
1886     pbSquare->hide();
1887     pbPower->hide();
1888     pbCube->hide();
1889     pbEE->hide();
1890 
1891     // delete the constant menu since it doesn't fit
1892     delete constants_menu_;
1893     constants_menu_ = nullptr;
1894 
1895     KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::simple);
1896     // must be done after setting the calculator mode because the
1897     // slotBitsetshow slot should save the state only in numeral mode
1898     action_bitset_show_->setChecked(false);
1899 }
1900 
1901 //------------------------------------------------------------------------------
1902 // Name: slotSetScienceMode
1903 // Desc: sets the calculator to science mode
1904 //------------------------------------------------------------------------------
slotSetScienceMode()1905 void KCalculator::slotSetScienceMode()
1906 {
1907     action_constants_show_->setEnabled(true);
1908     action_constants_show_->setChecked(KCalcSettings::showConstants());
1909     action_bitset_show_->setEnabled(false);
1910     action_history_show_->setChecked(KCalcSettings::showHistory());
1911 
1912     // show some individual buttons
1913     pbShift->show();
1914     pbMod->show();
1915     pbReci->show();
1916     pbFactorial->show();
1917     pbSquare->show();
1918     pbPower->show();
1919     pbCube->show();
1920     pbEE->show();
1921 
1922     // show or hide some groups of buttons
1923     showMemButtons(true);
1924     showScienceButtons(true);
1925     showStatButtons(false);
1926     showLogicButtons(false);
1927 
1928     if (!constants_menu_) {
1929         constants_menu_ = createConstantsMenu();
1930         menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
1931     }
1932 
1933     KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::science);
1934     // must be done after setting the calculator mode because the
1935     // slotBitsetshow slot should save the state only in numeral mode
1936     action_bitset_show_->setChecked(false);
1937 }
1938 
1939 //------------------------------------------------------------------------------
1940 // Name: slotSetStatisticMode
1941 // Desc: sets the calculator to stats mode
1942 //------------------------------------------------------------------------------
slotSetStatisticMode()1943 void KCalculator::slotSetStatisticMode()
1944 {
1945     action_constants_show_->setEnabled(true);
1946     action_constants_show_->setChecked(KCalcSettings::showConstants());
1947     action_bitset_show_->setEnabled(false);
1948     action_history_show_->setChecked(KCalcSettings::showHistory());
1949 
1950     // show some individual buttons
1951     pbShift->show();
1952     pbMod->show();
1953     pbReci->show();
1954     pbFactorial->show();
1955     pbSquare->show();
1956     pbPower->show();
1957     pbCube->show();
1958     pbEE->show();
1959 
1960     // show or hide some groups of buttons
1961     showMemButtons(true);
1962     showScienceButtons(true);
1963     showStatButtons(true);
1964     showLogicButtons(false);
1965 
1966     if (!constants_menu_) {
1967         constants_menu_ = createConstantsMenu();
1968         menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
1969     }
1970 
1971     KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::statistics);
1972     // must be done after setting the calculator mode because the
1973     // slotBitsetshow slot should save the state only in numeral mode
1974     action_bitset_show_->setChecked(false);
1975 }
1976 
1977 //------------------------------------------------------------------------------
1978 // Name: slotSetNumeralMode
1979 // Desc: sets the calculator to numerical ("programmers") mode
1980 //------------------------------------------------------------------------------
slotSetNumeralMode()1981 void KCalculator::slotSetNumeralMode()
1982 {
1983     action_constants_show_->setChecked(false);
1984     action_constants_show_->setEnabled(false);
1985     action_bitset_show_->setEnabled(true);
1986     action_bitset_show_->setChecked(KCalcSettings::showBitset());
1987     action_history_show_->setChecked(KCalcSettings::showHistory());
1988 
1989     // show some individual buttons
1990     pbShift->show();
1991     pbMod->show();
1992     pbReci->show();
1993     pbFactorial->show();
1994     pbSquare->show();
1995     pbPower->show();
1996     pbCube->show();
1997     pbEE->show();
1998 
1999     // show or hide some groups of buttons
2000     showMemButtons(true);
2001     showScienceButtons(false);
2002     showStatButtons(false);
2003     showLogicButtons(true);
2004 
2005     if (!constants_menu_) {
2006         constants_menu_ = createConstantsMenu();
2007         menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_);
2008     }
2009 
2010     KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::numeral);
2011 }
2012 
2013 //------------------------------------------------------------------------------
2014 // Name: slotBaseModeAmountChanged
2015 // Desc: updates numerical base conversions
2016 //------------------------------------------------------------------------------
slotBaseModeAmountChanged(const KNumber & number)2017 void KCalculator::slotBaseModeAmountChanged(const KNumber &number)
2018 {
2019     quint64 n = number.toUint64();
2020 
2021     decDisplay->setText(QString::number(n, 10));
2022     binDisplay->setText(QString::number(n, 2));
2023     octDisplay->setText(QString::number(n, 8));
2024     hexDisplay->setText(QString::number(n, 16).toUpper());
2025 }
2026 
2027 //------------------------------------------------------------------------------
2028 // Name: showMemButtons
2029 // Desc: hides or shows the memory buttons
2030 //------------------------------------------------------------------------------
showMemButtons(bool toggled)2031 void KCalculator::showMemButtons(bool toggled)
2032 {
2033     if (toggled) {
2034         for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2035             btn->show();
2036         }
2037     } else {
2038         for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2039             btn->hide();
2040         }
2041 
2042         // these are in the mem_button_list_ but should not be hidden
2043         pbClear->show();
2044         pbAllClear->show();
2045     }
2046 }
2047 
2048 //------------------------------------------------------------------------------
2049 // Name: showStatButtons
2050 // Desc: hides or shows the stat buttons
2051 //------------------------------------------------------------------------------
showStatButtons(bool toggled)2052 void KCalculator::showStatButtons(bool toggled)
2053 {
2054     if (toggled) {
2055         for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2056             btn->show();
2057         }
2058     } else {
2059         for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2060             btn->hide();
2061         }
2062     }
2063 }
2064 
2065 //------------------------------------------------------------------------------
2066 // Name: showScienceButtons
2067 // Desc: hides or shows the science buttons
2068 //------------------------------------------------------------------------------
showScienceButtons(bool toggled)2069 void KCalculator::showScienceButtons(bool toggled)
2070 {
2071     if (toggled) {
2072         for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
2073             btn->show();
2074         }
2075         const auto buttons = angle_choose_group_->buttons();
2076         for (QAbstractButton *btn : buttons) {
2077             btn->show();
2078         }
2079 
2080         setAngle();
2081         statusBar()->setAngleModeIndicatorVisible(true);
2082     } else {
2083         for (QAbstractButton *btn : std::as_const(scientific_buttons_)) {
2084             btn->hide();
2085         }
2086 
2087         const auto buttons = angle_choose_group_->buttons();
2088         for (QAbstractButton *btn : buttons) {
2089             btn->hide();
2090         }
2091 
2092         statusBar()->setAngleModeIndicatorVisible(false);
2093         calc_display->setStatusText(AngleField, QString());
2094     }
2095 }
2096 
2097 //------------------------------------------------------------------------------
2098 // Name: showLogicButtons
2099 // Desc: hides or shows the logic buttons
2100 //------------------------------------------------------------------------------
showLogicButtons(bool toggled)2101 void KCalculator::showLogicButtons(bool toggled)
2102 {
2103     if (toggled) {
2104         mBitset->setEnabled(true);
2105         connect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged);
2106         connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset);
2107 
2108         for (QAbstractButton *btn : std::as_const(logic_buttons_)) {
2109             btn->show();
2110         }
2111 
2112         setBase();
2113         statusBar()->setBaseIndicatorVisible(true);
2114 
2115         const auto buttons = base_choose_group_->buttons();
2116         for (QAbstractButton *btn : buttons) {
2117             btn->show();
2118         }
2119 
2120         for (QLabel *lbl : base_conversion_labels_) {
2121             lbl->show();
2122         }
2123         connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotBaseModeAmountChanged);
2124 
2125         for (int i = 10; i < 16; ++i) {
2126             (num_button_group_->button(i))->show();
2127         }
2128     } else {
2129         mBitset->setEnabled(false);
2130         disconnect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged);
2131         disconnect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset);
2132 
2133         for (QAbstractButton *btn : std::as_const(logic_buttons_)) {
2134             btn->hide();
2135         }
2136 
2137         // Hide Hex-Buttons, but first switch back to decimal
2138         decRadio->animateClick(0);
2139 
2140         const auto buttons = base_choose_group_->buttons();
2141         for (QAbstractButton *btn : buttons) {
2142             btn->hide();
2143         }
2144 
2145         for (QLabel *lbl : base_conversion_labels_) {
2146             lbl->hide();
2147         }
2148         connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotBaseModeAmountChanged);
2149 
2150         statusBar()->setBaseIndicatorVisible(false);
2151         calc_display->setStatusText(BaseField, QString());
2152         for (int i = 10; i < 16; ++i) {
2153             (num_button_group_->button(i))->hide();
2154         }
2155     }
2156 }
2157 
2158 //------------------------------------------------------------------------------
2159 // Name: slotHistoryshow
2160 // Desc: hides or shows the history
2161 //------------------------------------------------------------------------------
slotHistoryshow(bool toggled)2162 void KCalculator::slotHistoryshow(bool toggled) {
2163 
2164     calc_history->setVisible(toggled);
2165     KCalcSettings::setShowHistory(toggled);
2166 }
2167 
2168 //------------------------------------------------------------------------------
2169 // Name: slotConstantsShow
2170 // Desc: hides or shows the constants buttons
2171 //------------------------------------------------------------------------------
slotConstantsShow(bool toggled)2172 void KCalculator::slotConstantsShow(bool toggled)
2173 {
2174     if (toggled) {
2175         for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2176             btn->show();
2177         }
2178     } else {
2179         for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2180             btn->hide();
2181         }
2182     }
2183 
2184     KCalcSettings::setShowConstants(toggled);
2185 }
2186 
2187 //------------------------------------------------------------------------------
2188 // Name: slotBitsetshow
2189 // Desc: hides or shows the bitset buttons
2190 //------------------------------------------------------------------------------
slotBitsetshow(bool toggled)2191 void KCalculator::slotBitsetshow(bool toggled)
2192 {
2193     mBitset->setVisible(toggled);
2194     if (KCalcSettings::calculatorMode() == KCalcSettings::EnumCalculatorMode::numeral) {
2195         KCalcSettings::setShowBitset(toggled);
2196     }
2197 }
2198 
2199 //------------------------------------------------------------------------------
2200 // Name: slotBitsetshow
2201 // Desc: This function is for setting the constant names configured in the
2202 //       kcalc settings menu. If the user doesn't enter a name for the
2203 //       constant C1 to C6 is used.
2204 //------------------------------------------------------------------------------
changeButtonNames()2205 void KCalculator::changeButtonNames()
2206 {
2207     for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2208         if (auto const constbtn = qobject_cast<KCalcConstButton *>(btn)) {
2209             constbtn->setLabelAndTooltip();
2210         }
2211     }
2212 }
2213 
2214 //------------------------------------------------------------------------------
2215 // Name: slotBitsetChanged
2216 // Desc: updates the bitset display
2217 // NOTE: sets display to *unsigned* value
2218 //------------------------------------------------------------------------------
slotBitsetChanged(quint64 value)2219 void KCalculator::slotBitsetChanged(quint64 value)
2220 {
2221     calc_display->setAmount(KNumber(value));
2222     updateDisplay({});
2223     core.setOnlyUpdateOperation(false);
2224 }
2225 
2226 //------------------------------------------------------------------------------
2227 // Name: slotUpdateBitset
2228 // Desc: updates the bitset itself
2229 //------------------------------------------------------------------------------
slotUpdateBitset(const KNumber & nr)2230 void KCalculator::slotUpdateBitset(const KNumber &nr)
2231 {
2232     mBitset->setValue(nr.toUint64());
2233 }
2234 
2235 //------------------------------------------------------------------------------
2236 // Name: updateSettings
2237 // Desc: updates the persistent settings
2238 //------------------------------------------------------------------------------
updateSettings()2239 void KCalculator::updateSettings()
2240 {
2241     changeButtonNames();
2242     setColors();
2243     setFonts();
2244     setPrecision();
2245 
2246     // Show the result in the app's caption in taskbar (wishlist - bug #52858)
2247     disconnect(calc_display, SIGNAL(changedText(QString)), this, nullptr);
2248 
2249     if (KCalcSettings::captionResult()) {
2250         connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle);
2251     } else {
2252         setCaption(QString());
2253     }
2254 
2255     calc_display->changeSettings();
2256     calc_history->changeSettings();
2257     updateGeometry();
2258 }
2259 
2260 //------------------------------------------------------------------------------
2261 // Name: updateDisplay
2262 // Desc: updates the display
2263 //------------------------------------------------------------------------------
2264 
updateDisplay(UpdateFlags flags)2265 void KCalculator::updateDisplay(UpdateFlags flags)
2266 {
2267     if (flags & UPDATE_FROM_CORE) {
2268         if (update_history_window_) {
2269             calc_history->addToHistory(calc_display->getAmount().toQString(KCalcSettings::precision()), false);
2270         } else {
2271             update_history_window_ = true;
2272         }
2273         calc_display->updateFromCore(core, (flags & UPDATE_STORE_RESULT) != 0);
2274     } else {
2275         calc_display->update();
2276     }
2277 
2278     pbShift->setChecked(false);
2279 }
2280 
2281 //------------------------------------------------------------------------------
2282 // Name: updateHistoryWithFunction
2283 // Desc: updates the history with the last used function
2284 //------------------------------------------------------------------------------
updateHistoryWithFunction(CalcEngine::Operation func)2285 void KCalculator::updateHistoryWithFunction(CalcEngine::Operation func) {
2286     calc_history->addFuncToHistory(func);
2287 }
2288 
2289 //------------------------------------------------------------------------------
2290 // Name: setColors
2291 // Desc: set the various colours
2292 //------------------------------------------------------------------------------
setColors()2293 void KCalculator::setColors()
2294 {
2295     calc_display->changeSettings();
2296     calc_history->changeSettings();
2297 
2298     const QColor numFontColor(KCalcSettings::numberFontsColor());
2299     for (int i = 0; i < 10; ++i) {
2300         qobject_cast<KCalcButton *>((num_button_group_->button(i)))->setTextColor(numFontColor);
2301     }
2302 
2303     const QColor funcFontColor(KCalcSettings::functionFontsColor());
2304     for (QAbstractButton *btn : std::as_const(function_button_list_)) {
2305         qobject_cast<KCalcButton *>(btn)->setTextColor(funcFontColor);
2306     }
2307 
2308     const QColor statFontColor(KCalcSettings::statFontsColor());
2309     for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2310         qobject_cast<KCalcButton *>(btn)->setTextColor(statFontColor);
2311     }
2312 
2313     const QColor hexFontColor(KCalcSettings::hexFontsColor());
2314     for (int i = 10; i < 16; ++i) {
2315         qobject_cast<KCalcButton *>((num_button_group_->button(i)))->setTextColor(hexFontColor);
2316     }
2317 
2318     const QColor memFontColor(KCalcSettings::memoryFontsColor());
2319     for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2320         qobject_cast<KCalcButton *>(btn)->setTextColor(memFontColor);
2321     }
2322 
2323     const QColor opFontColor(KCalcSettings::operationFontsColor());
2324     for (QAbstractButton *btn : std::as_const(operation_button_list_)) {
2325         qobject_cast<KCalcButton *>(btn)->setTextColor(opFontColor);
2326     }
2327 
2328     const QColor coFontColor(KCalcSettings::constantsFontsColor());
2329     for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2330         qobject_cast<KCalcButton *>(btn)->setTextColor(coFontColor);
2331     }
2332 
2333     KColorScheme schemeButtons(QPalette::Active, KColorScheme::Button);
2334     const QColor defaultColor = schemeButtons.background().color();
2335 
2336     // Do not apply style sheets when using default background colors, see bug 237513
2337     if (KCalcSettings::numberButtonsColor() == defaultColor && KCalcSettings::functionButtonsColor() == defaultColor
2338         && KCalcSettings::statButtonsColor() == defaultColor && KCalcSettings::hexButtonsColor() == defaultColor
2339         && KCalcSettings::memoryButtonsColor() == defaultColor && KCalcSettings::operationButtonsColor() == defaultColor
2340         && KCalcSettings::constantsButtonsColor() == defaultColor) {
2341         return;
2342     }
2343 
2344     const QString sheet = QStringLiteral("QPushButton { background-color: %1 }");
2345 
2346     const QColor numPal(KCalcSettings::numberButtonsColor());
2347     for (int i = 0; i < 10; ++i) {
2348         (num_button_group_->button(i))->setStyleSheet(sheet.arg(numPal.name()));
2349     }
2350 
2351     const QColor funcPal(KCalcSettings::functionButtonsColor());
2352     for (QAbstractButton *btn : std::as_const(function_button_list_)) {
2353         btn->setStyleSheet(sheet.arg(funcPal.name()));
2354     }
2355 
2356     const QColor statPal(KCalcSettings::statButtonsColor());
2357     for (QAbstractButton *btn : std::as_const(stat_buttons_)) {
2358         btn->setStyleSheet(sheet.arg(statPal.name()));
2359     }
2360 
2361     const QColor hexPal(KCalcSettings::hexButtonsColor());
2362     for (int i = 10; i < 16; ++i) {
2363         (num_button_group_->button(i))->setStyleSheet(sheet.arg(hexPal.name()));
2364     }
2365 
2366     const QColor memPal(KCalcSettings::memoryButtonsColor());
2367     for (QAbstractButton *btn : std::as_const(mem_button_list_)) {
2368         btn->setStyleSheet(sheet.arg(memPal.name()));
2369     }
2370 
2371     const QColor opPal(KCalcSettings::operationButtonsColor());
2372     for (QAbstractButton *btn : std::as_const(operation_button_list_)) {
2373         btn->setStyleSheet(sheet.arg(opPal.name()));
2374     }
2375 
2376     const QColor coPal(KCalcSettings::constantsButtonsColor());
2377     for (QAbstractButton *btn : std::as_const(const_buttons_)) {
2378         btn->setStyleSheet(sheet.arg(coPal.name()));
2379     }
2380 }
2381 
2382 //------------------------------------------------------------------------------
2383 // Name: setFonts
2384 // Desc: set the various fonts
2385 //------------------------------------------------------------------------------
setFonts()2386 void KCalculator::setFonts()
2387 {
2388     const auto leftPadLst = leftPad->children();
2389     for (QObject *obj : leftPadLst) {
2390         if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2391             button->setFont(KCalcSettings::buttonFont());
2392         }
2393     }
2394 
2395     const auto numericPadLst = numericPad->children();
2396     for (QObject *obj : numericPadLst) {
2397         if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2398             button->setFont(KCalcSettings::buttonFont());
2399         }
2400     }
2401 
2402     const auto rightPadLst = rightPad->children();
2403     for (QObject *obj : rightPadLst) {
2404         if (auto const button = qobject_cast<KCalcButton *>(obj)) {
2405             button->setFont(KCalcSettings::buttonFont());
2406         }
2407     }
2408 
2409     updateGeometry();
2410 }
2411 
2412 //------------------------------------------------------------------------------
2413 // Name: event
2414 // Desc: catch application's palette and font change events
2415 //------------------------------------------------------------------------------
event(QEvent * e)2416 bool KCalculator::event(QEvent *e)
2417 {
2418     switch (e->type()) {
2419     case QEvent::ApplicationFontChange:
2420         setFonts();
2421         break;
2422     case QEvent::ApplicationPaletteChange:
2423         setColors();
2424         break;
2425     default:
2426         break;
2427     }
2428     return KXmlGuiWindow::event(e);
2429 }
2430 
2431 //------------------------------------------------------------------------------
2432 // Name: setPrecision
2433 // Desc: set the precision of the display
2434 //------------------------------------------------------------------------------
setPrecision()2435 void KCalculator::setPrecision()
2436 {
2437     KNumber::setDefaultFloatPrecision(KCalcSettings::precision());
2438     updateDisplay({});
2439 }
2440 
2441 //------------------------------------------------------------------------------
2442 // Name: setAngle
2443 // Desc: sets the angle mode
2444 //------------------------------------------------------------------------------
setAngle()2445 void KCalculator::setAngle()
2446 {
2447     if (QAbstractButton *const btn = angle_choose_group_->button(KCalcSettings::angleMode())) {
2448         btn->animateClick(0);
2449     }
2450 }
2451 
2452 //------------------------------------------------------------------------------
2453 // Name: setBase
2454 // Desc: sets the numeric base
2455 //------------------------------------------------------------------------------
setBase()2456 void KCalculator::setBase()
2457 {
2458     if (QAbstractButton *const btn = base_choose_group_->button(KCalcSettings::baseMode())) {
2459         btn->animateClick(0);
2460     }
2461 }
2462 
2463 //------------------------------------------------------------------------------
2464 // Name: eventFilter
2465 // Desc: general event filter used to track events like drag/drop
2466 //------------------------------------------------------------------------------
eventFilter(QObject * o,QEvent * e)2467 bool KCalculator::eventFilter(QObject *o, QEvent *e)
2468 {
2469     switch (e->type()) {
2470     case QEvent::DragEnter: {
2471         auto const ev = reinterpret_cast<QDragEnterEvent *>(e);
2472         ev->setAccepted(KColorMimeData::canDecode(ev->mimeData()));
2473         return true;
2474     }
2475     case QEvent::DragLeave: {
2476         return true;
2477     }
2478     case QEvent::Drop: {
2479         auto const calcButton = qobject_cast<KCalcButton *>(o);
2480         if (!calcButton) {
2481             return false;
2482         }
2483 
2484         auto const ev = reinterpret_cast<QDropEvent *>(e);
2485         QColor c = KColorMimeData::fromMimeData(ev->mimeData());
2486 
2487         if (c.isValid()) {
2488             QString cn = c.name();
2489             QString sheet = QStringLiteral("background-color: %1");
2490 
2491             QList<QAbstractButton *> *list;
2492             const int num_but = num_button_group_->buttons().indexOf(calcButton);
2493             if (num_but != -1) {
2494                 // Was it hex-button or normal digit??
2495                 if (num_but < 10) {
2496                     for (int i = 0; i < 10; ++i) {
2497                         (num_button_group_->buttons().at(i))->setStyleSheet(sheet.arg(cn));
2498                     }
2499                 } else {
2500                     for (int i = 10; i < 16; ++i) {
2501                         (num_button_group_->buttons().at(i))->setStyleSheet(sheet.arg(cn));
2502                     }
2503                 }
2504                 return true;
2505             } else if (function_button_list_.contains(calcButton)) {
2506                 list = &function_button_list_;
2507             } else if (stat_button_list_.contains(calcButton)) {
2508                 list = &stat_button_list_;
2509             } else if (mem_button_list_.contains(calcButton)) {
2510                 list = &mem_button_list_;
2511             } else if (operation_button_list_.contains(calcButton)) {
2512                 list = &operation_button_list_;
2513             } else {
2514                 return false;
2515             }
2516 
2517             for (int i = 0; i < list->size(); ++i) {
2518                 list->at(i)->setStyleSheet(sheet.arg(cn));
2519             }
2520         }
2521         return true;
2522     }
2523     // FALL THROUGH
2524     default:
2525         return KXmlGuiWindow::eventFilter(o, e);
2526     }
2527 }
2528 
2529 //------------------------------------------------------------------------------
2530 // Name: slotPaste
2531 // Desc: paste a number from the clipboard
2532 //------------------------------------------------------------------------------
slotPaste()2533 void KCalculator::slotPaste()
2534 {
2535     calc_display->slotPaste();
2536     core.setOnlyUpdateOperation(false);
2537 }
2538 
2539 ////////////////////////////////////////////////////////////////
2540 // Include the meta-object code for classes in this file
2541 //
2542 
2543 //------------------------------------------------------------------------------
2544 // Name: main
2545 // Desc: entry point of the application
2546 //------------------------------------------------------------------------------
main(int argc,char * argv[])2547 int main(int argc, char *argv[])
2548 {
2549     QApplication app(argc, argv);
2550 
2551     KLocalizedString::setApplicationDomain("kcalc");
2552 
2553     /**
2554      * enable high dpi support
2555      */
2556     app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
2557     KCrash::initialize();
2558     Kdelibs4ConfigMigrator migrate(QStringLiteral("kcalc"));
2559     migrate.setConfigFiles(QStringList() << QStringLiteral("kcalcrc"));
2560     migrate.setUiFiles(QStringList() << QStringLiteral("kcalcui.rc"));
2561     migrate.migrate();
2562 
2563     KAboutData aboutData(QStringLiteral("kcalc"),
2564                          i18n("KCalc"),
2565                          QStringLiteral(KCALC_VERSION_STRING),
2566                          i18n(description),
2567                          KAboutLicense::GPL,
2568                          i18n("Copyright © 2008-2013, Evan Teran\n"
2569                               "Copyright © 2000-2008, The KDE Team\n"
2570                               "Copyright © 2003-2005, Klaus Niederkr"
2571                               "\xc3\xbc"
2572                               "ger\n"
2573                               "Copyright © 1996-2000, Bernd Johannes Wuebben"),
2574                          QString(),
2575                          QStringLiteral("https://utils.kde.org/projects/kcalc"));
2576 
2577     // Klaus Niederkrueger
2578     aboutData.addAuthor(i18n("Klaus Niederkr"
2579                              "\xc3\xbc"
2580                              "ger"),
2581                         QString(),
2582                         QStringLiteral("kniederk@math.uni-koeln.de"));
2583     aboutData.addAuthor(i18n("Bernd Johannes Wuebben"), QString(), QStringLiteral("wuebben@kde.org"));
2584     aboutData.addAuthor(i18n("Evan Teran"), i18n("Maintainer"), QStringLiteral("eteran@alum.rit.edu"));
2585     aboutData.addAuthor(i18n("Espen Sand"), QString(), QStringLiteral("espen@kde.org"));
2586     aboutData.addAuthor(i18n("Chris Howells"), QString(), QStringLiteral("howells@kde.org"));
2587     aboutData.addAuthor(i18n("Aaron J. Seigo"), QString(), QStringLiteral("aseigo@olympusproject.org"));
2588     aboutData.addAuthor(i18n("Charles Samuels"), QString(), QStringLiteral("charles@altair.dhs.org"));
2589     // Rene Merou
2590     aboutData.addAuthor(i18n("Ren"
2591                              "\xc3\xa9"
2592                              " M"
2593                              "\xc3\xa9"
2594                              "rou"),
2595                         QString(),
2596                         QStringLiteral("ochominutosdearco@yahoo.es"));
2597     aboutData.addAuthor(i18n("Michel Marti"), QString(), QStringLiteral("mma@objectxp.com"));
2598     aboutData.addAuthor(i18n("David Johnson"), QString(), QStringLiteral("david@usermode.org"));
2599 
2600     KAboutData::setApplicationData(aboutData);
2601     app.setWindowIcon(QIcon::fromTheme(QStringLiteral("accessories-calculator"), app.windowIcon()));
2602 
2603     QCommandLineParser parser;
2604     aboutData.setupCommandLine(&parser);
2605     parser.process(app);
2606     aboutData.processCommandLine(&parser);
2607 
2608     // force system locale to "C" internally [bug 159168]
2609     setlocale(LC_NUMERIC, "C");
2610 
2611     KNumber::setGroupSeparator(QLocale().groupSeparator());
2612     KNumber::setDecimalSeparator(QString(QLocale().decimalPoint()));
2613 
2614     auto calc = new KCalculator(nullptr);
2615 
2616     calc->show();
2617     return app.exec();
2618 }
2619