summaryrefslogtreecommitdiffstats
path: root/katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp')
-rw-r--r--katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp360
1 files changed, 360 insertions, 0 deletions
diff --git a/katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp b/katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp
new file mode 100644
index 0000000..c3c5f6d
--- /dev/null
+++ b/katapult/plugins/catalogs/calculatorcatalog/calculatorcatalog.cpp
@@ -0,0 +1,360 @@
+/***************************************************************************
+ * Copyright (C) 2005 Tobi Vollebregt *
+ * tobivollebregt@gmail.com *
+ * *
+ * Copyright (C) 2005 by Joe Ferris *
+ * jferris@optimistictech.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include <kservicegroup.h>
+#include <ksycocaentry.h>
+#include <ksycocatype.h>
+#include <kapplication.h>
+#include <knuminput.h>
+#include <kcombobox.h>
+
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qregexp.h>
+
+#include <math.h>
+
+#include "settings.h"
+#include "calculatorcatalog.h"
+#include "expression.h"
+#include "actionregistry.h"
+#include "actionevalexpr.h"
+#include "status.h"
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+
+
+static double frac(double x)
+{
+ double nowhere;
+ return modf(x, &nowhere);
+}
+
+
+static double deg_sin(double x) { return sin(x * (M_PI / 180.0)); }
+static double deg_cos(double x) { return cos(x * (M_PI / 180.0)); }
+static double deg_tan(double x) { return tan(x * (M_PI / 180.0)); }
+static double deg_asin(double x) { return asin(x) * (180.0 / M_PI); }
+static double deg_acos(double x) { return acos(x) * (180.0 / M_PI); }
+static double deg_atan(double x) { return atan(x) * (180.0 / M_PI); }
+static double deg_sinh(double x) { return sinh(x * (M_PI / 180.0)); }
+static double deg_cosh(double x) { return cosh(x * (M_PI / 180.0)); }
+static double deg_tanh(double x) { return tanh(x * (M_PI / 180.0)); }
+static double deg_asinh(double x) { return asinh(x) * (180.0 / M_PI); }
+static double deg_acosh(double x) { return acosh(x) * (180.0 / M_PI); }
+static double deg_atanh(double x) { return atanh(x) * (180.0 / M_PI); }
+
+
+const CalculatorCatalog::Function CalculatorCatalog::radiansFunctionTable[] =
+{
+ { "sin", 3, sin },
+ { "cos", 3, cos },
+ { "tan", 3, tan },
+ { "asin", 4, asin },
+ { "acos", 4, acos },
+ { "atan", 4, atan },
+ { "sinh", 4, sinh },
+ { "cosh", 4, cosh },
+ { "tanh", 4, tanh },
+ { "asinh", 5, asinh },
+ { "acosh", 5, acosh },
+ { "atanh", 5, atanh },
+ { "sqrt", 4, sqrt },
+ { "log", 3, log10 },
+ { "ln", 2, log },
+ { "exp", 3, exp },
+ { "abs", 3, fabs },
+ { "frac", 4, frac },
+ { "round", 5, round },
+ { "int", 3, trunc },
+ { 0, 0, 0 }
+};
+
+const CalculatorCatalog::Function CalculatorCatalog::degreesFunctionTable[] =
+{
+ { "sin", 3, deg_sin },
+ { "cos", 3, deg_cos },
+ { "tan", 3, deg_tan },
+ { "asin", 4, deg_asin },
+ { "acos", 4, deg_acos },
+ { "atan", 4, deg_atan },
+ { "sinh", 4, deg_sinh },
+ { "cosh", 4, deg_cosh },
+ { "tanh", 4, deg_tanh },
+ { "asinh", 5, deg_asinh },
+ { "acosh", 5, deg_acosh },
+ { "atanh", 5, deg_atanh },
+ { "sqrt", 4, sqrt },
+ { "log", 3, log10 },
+ { "ln", 2, log },
+ { "exp", 3, exp },
+ { "abs", 3, fabs },
+ { "frac", 4, frac },
+ { "round", 5, round },
+ { "int", 3, trunc },
+ { 0, 0, 0 }
+};
+
+
+K_EXPORT_COMPONENT_FACTORY( katapult_calculatorcatalog,
+ KGenericFactory<CalculatorCatalog>( "katapult_calculatorcatalog" ) )
+
+CalculatorCatalog::CalculatorCatalog(QObject*, const char*, const QStringList&): _result(this, QString::null)
+{
+ ActionRegistry::self()->registerAction(new ActionEvaluateExpression());
+
+ setVar(getVarID("pi"), M_PI);
+ setVar(getVarID("e"), M_E);
+}
+
+CalculatorCatalog::~CalculatorCatalog()
+{
+}
+
+void CalculatorCatalog::queryChanged()
+{
+ int newStatus = 0;
+ QString cmd = query();
+
+ if (cmd.isEmpty()) {
+ reset();
+ setBestMatch(Match());
+ } else {
+ if (accepts(cmd)) {
+ int i, origLength = cmd.length(), length = origLength;
+ //autocomplete functions
+ cmd = cmd.lower();
+ for (i = length - 1; i >= 0 && cmd[i].isLetter(); --i) { }
+ if (i != length - 1) {
+ QString start = cmd.mid(i + 1);
+ int lengthOfShortest = 9999, shortest = -1;
+ for (int j = 0; radiansFunctionTable[j].name; ++j) {
+ if (QString(radiansFunctionTable[j].name).startsWith(start)) {
+ if (radiansFunctionTable[j].length < lengthOfShortest) {
+ lengthOfShortest = radiansFunctionTable[j].length;
+ shortest = j;
+ }
+ }
+ }
+ if (shortest != -1) {
+ cmd = cmd.left(i + 1).append(radiansFunctionTable[shortest].name).append("(");
+ length = cmd.length();
+ }
+ }
+ //fix parse errors at end of expression,
+ //ie. close open parentheses, convert operators into NOPs
+ for (i = length - 1; i >= 0 && (cmd[i] == '(' || cmd[i] == ' '); --i) { }
+ if (i < 0 || cmd[i] == '+' || cmd[i] == '-') {
+ cmd.append("0");
+ ++length;
+ } else if (cmd[i] == '*' || cmd[i] == '/' || cmd[i] == '^') {
+ cmd.append("1");
+ ++length;
+ } else if (cmd[i].isLetter() && (i < length - 1 && cmd[i + 1] == '(')) {
+ //just add a 0 if it's a function: we don't bother to backpropagate
+ //through the parse tree (if it existed at all) to figure out a NOP value
+ //for this particular (chain of) function(s).
+ cmd.append("0");
+ ++length;
+ }
+ int openParen = 0;
+ //use cmd.length() here, it may be > than length.
+ for (i = 0; i < length; ++i) {
+ if (cmd[i] == '(') ++openParen;
+ if (cmd[i] == ')') --openParen;
+ }
+ if (openParen > 0) {
+ char* closeParen = new char[openParen + 1];
+ memset(closeParen, ')', openParen);
+ closeParen[openParen] = 0;
+ cmd.append(closeParen);
+ delete[] closeParen;
+ }
+ _result.setText(cmd);
+ setBestMatch(Match(&_result, _result.parseError() ? 10 : 100, origLength));
+ //set status.
+ //add S_Multiple to make sure katapult doesn't auto-exec and close the window
+ //add S_Active to make sure katapult doesn't start the hideTimer or clearTimer
+ newStatus = S_HasResults | S_Multiple | S_Active;
+ } else {
+ newStatus = 0;
+ }
+ }
+ setStatus(newStatus);
+}
+
+void CalculatorCatalog::reset()
+{
+ _result.setText(QString::null);
+}
+
+bool CalculatorCatalog::accepts(const QString& str) const
+{
+ //Heuristic to determine whether the string is an expression or not.
+ //Accept anything containing [()+\\-/*^=.,0-9].
+ return QRegExp("[()+\\-/*^=.,0-9]").search(str) >= 0;
+}
+
+int CalculatorCatalog::getVarID(const char* name)
+{
+ VarNameToIdMap::iterator it = varNameToId.find(QString(name));
+ if (it == varNameToId.end()) {
+ _pendingVarName = QString(name);
+ return -1;
+ }
+ return *it;
+}
+
+double CalculatorCatalog::getVar(int id) const
+{
+ return varIdToValue[id];
+}
+
+double CalculatorCatalog::setVar(int id, double value)
+{
+ if (id == -1) {
+ id = varIdToValue.count();
+ varNameToId.insert(_pendingVarName, id);
+ varIdToValue.push_back(value);
+ } else {
+ varIdToValue[id] = value;
+ }
+ return value;
+}
+
+/*
+void CalculatorCatalog::initialize()
+{
+}
+*/
+
+void CalculatorCatalog::readSettings(KConfigBase* config)
+{
+ _fracDigits = config->readUnsignedNumEntry("FracDigits", 2);
+ _bScientific = config->readBoolEntry("Scientific", false);
+ _bDegrees = config->readBoolEntry("Degrees", false);
+ _bClipboard = config->readBoolEntry("Clipboard", true);
+ _formatString = config->readEntry("FormatString", "%1 = %2");
+}
+
+void CalculatorCatalog::writeSettings(KConfigBase* config)
+{
+ config->writeEntry("FracDigits", fracDigits());
+ config->writeEntry("Scientific", scientific());
+ config->writeEntry("Degrees", degrees());
+ config->writeEntry("Clipboard", clipboard());
+ config->writeEntry("FormatString", formatString());
+}
+
+QWidget * CalculatorCatalog::configure()
+{
+ CalculatorCatalogSettings* settings = new CalculatorCatalogSettings();
+
+ settings->fracDigits->setValue(_fracDigits);
+ connect(settings->fracDigits, SIGNAL(valueChanged(int)), this, SLOT(fracDigitsChanged(int)));
+
+ settings->normal->setChecked(!scientific());
+ settings->scientific->setChecked(scientific());
+ connect(settings->scientific, SIGNAL(toggled(bool)), this, SLOT(scientificChanged(bool)));
+
+ settings->radians->setChecked(!degrees());
+ settings->degrees->setChecked(degrees());
+ connect(settings->degrees, SIGNAL(toggled(bool)), this, SLOT(degreesChanged(bool)));
+
+ settings->clipboard->setChecked(clipboard());
+ connect(settings->clipboard, SIGNAL(toggled(bool)), this, SLOT(clipboardChanged(bool)));
+
+ settings->formatString->setText(formatString());
+ connect(settings->formatString, SIGNAL(textChanged(const QString&)), this, SLOT(formatStringChanged(const QString&)));
+
+ return settings;
+}
+
+void CalculatorCatalog::fracDigitsChanged(int n)
+{
+ _fracDigits = n;
+}
+
+int CalculatorCatalog::fracDigits() const
+{
+ return _fracDigits;
+}
+
+void CalculatorCatalog::scientificChanged(bool en)
+{
+ _bScientific = en;
+}
+
+bool CalculatorCatalog::scientific() const
+{
+ return _bScientific;
+}
+
+void CalculatorCatalog::degreesChanged(bool en)
+{
+ _bDegrees = en;
+}
+
+bool CalculatorCatalog::degrees() const
+{
+ return _bDegrees;
+}
+
+void CalculatorCatalog::formatStringChanged(const QString& fmt)
+{
+ _formatString = fmt;
+}
+
+QString CalculatorCatalog::formatString() const
+{
+ return _formatString;
+}
+
+void CalculatorCatalog::clipboardChanged(bool en)
+{
+ _bClipboard = en;
+}
+
+bool CalculatorCatalog::clipboard() const
+{
+ return _bClipboard;
+}
+
+const CalculatorCatalog::Function* CalculatorCatalog::functionTable() const
+{
+ if (degrees()) {
+ return degreesFunctionTable;
+ } else {
+ return radiansFunctionTable;
+ }
+}
+
+#include "calculatorcatalog.moc"