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>√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("Γ"), 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("√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("Γ"));
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("√"));
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>√"));
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(" ^ 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