not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / runners / calculator / calculatorrunner.cpp
blobd7e7fbf8796259fd53ff0a1b094ef740eca5618c
1 /*
2 * Copyright (C) 2007 Barış Metin <baris@pardus.org.tr>
3 * Copyright (C) 2006 David Faure <faure@kde.org>
4 * Copyright (C) 2007 Richard Moore <rich@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License version 2 as
8 * published by the Free Software Foundation
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "calculatorrunner.h"
23 #include <QHBoxLayout>
24 #include <QLabel>
25 #include <QWidget>
26 #include <QScriptEngine>
28 #include <KIcon>
30 CalculatorRunner::CalculatorRunner( QObject* parent, const QVariantList &args )
31 : Plasma::AbstractRunner(parent, args)
33 Q_UNUSED(args)
35 setObjectName("Calculator");
36 setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File |
37 Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Executable |
38 Plasma::RunnerContext::ShellCommand);
41 CalculatorRunner::~CalculatorRunner()
45 void CalculatorRunner::powSubstitutions(QString& cmd)
47 if (cmd.contains("e+", Qt::CaseInsensitive)) {
48 cmd=cmd.replace("e+", "^", Qt::CaseInsensitive);
51 if (cmd.contains("e-", Qt::CaseInsensitive)) {
52 cmd=cmd.replace("e-", "^-", Qt::CaseInsensitive);
55 // the below code is scary mainly because we have to honor priority
56 // honor decimal numbers and parenthesis.
57 if (cmd.contains('^')){
58 int where = cmd.indexOf('^');
59 cmd = cmd.replace('^', ',');
60 int preIndex = where - 1;
61 int postIndex = where + 1;
62 int count = 0;
64 QChar decimalSymbol = KGlobal::locale()->decimalSymbol().at(0);
65 //avoid out of range on weird commands
66 preIndex = qMax(0, preIndex);
67 postIndex = qMin(postIndex, cmd.length()-1);
69 //go backwards looking for the beginning of the number or expression
70 while (preIndex != 0) {
71 QChar current = cmd.at(preIndex);
72 QChar next = cmd.at(preIndex-1);
73 //kDebug() << "index " << preIndex << " char " << current;
74 if (current == ')') {
75 count++;
76 } else if (current == '(') {
77 count--;
78 } else {
79 if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) {
80 preIndex--;
81 continue;
84 if (count == 0) {
85 break;
87 preIndex--;
90 //go forwards looking for the end of the number or expression
91 count = 0;
92 while (postIndex != cmd.size() - 1) {
93 QChar current=cmd.at(postIndex);
94 QChar next=cmd.at(postIndex + 1);
95 if (current == '(') {
96 count++;
97 } else if (current == ')') {
98 count--;
99 } else {
100 if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) {
101 postIndex++;
102 continue;
105 if (count == 0) {
106 break;
108 postIndex++;
111 preIndex = qMax(0, preIndex);
112 postIndex = qMin(postIndex, cmd.length());
114 cmd.insert(preIndex,"pow(");
115 // +1 +4 == next position to the last number after we add 4 new characters pow(
116 cmd.insert(postIndex + 1 + 4, ')');
117 //kDebug() << "from" << preIndex << " to " << postIndex << " got: " << cmd;
121 void CalculatorRunner::hexSubstitutions(QString& cmd)
123 if (cmd.contains("0x")) {
124 bool ok;
125 int pos = 0;
126 QString hex;
128 for (int i = 0; i < cmd.size(); i++) {
129 hex.clear();
130 pos = cmd.indexOf("0x", pos);
132 for (int q = 0; q < cmd.size(); q++) {//find end of hex number
133 QChar current = cmd[pos+q+2];
134 if (((current <= '9' ) && (current >= '0')) || ((current <= 'F' ) && (current >= 'A'))) { //Check if valid hex sign
135 hex[q] = current;
136 } else {
137 break;
140 cmd = cmd.replace("0x" + hex,QString::number(hex.toInt(&ok,16))); //replace hex with decimal
146 void CalculatorRunner::userFriendlySubstitutions(QString& cmd)
148 if (cmd.contains(KGlobal::locale()->decimalSymbol(), Qt::CaseInsensitive)) {
149 cmd=cmd.replace(KGlobal::locale()->decimalSymbol(), ".", Qt::CaseInsensitive);
152 hexSubstitutions(cmd);
153 powSubstitutions(cmd);
155 if (cmd.contains(QRegExp("\\d+and\\d+"))) {
156 cmd = cmd.replace(QRegExp("(\\d+)and(\\d+)"), "\\1&\\2");
158 if (cmd.contains(QRegExp("\\d+or\\d+"))) {
159 cmd = cmd.replace(QRegExp("(\\d+)or(\\d+)"), "\\1|\\2");
161 if (cmd.contains(QRegExp("\\d+xor\\d+"))) {
162 cmd = cmd.replace(QRegExp("(\\d+)xor(\\d+)"), "\\1^\\2");
167 void CalculatorRunner::match(Plasma::RunnerContext &context)
169 const QString term = context.query();
170 QString cmd = term;
172 //no meanless space between friendly guys: helps simplify code
173 cmd = cmd.trimmed().replace(" ", "");
175 if (cmd.length() < 4) {
176 return;
179 bool toHex = cmd.startsWith("hex=");
180 bool startsWithEquals = !toHex && cmd[0] == '=';
182 if (toHex || startsWithEquals) {
183 cmd.remove(0, cmd.indexOf('=') + 1);
184 } else if (cmd.endsWith('=')) {
185 cmd.chop(1);
186 } else {
187 // we don't have an actionable equation here
188 return;
191 if (cmd.isEmpty()) {
192 return;
195 userFriendlySubstitutions(cmd);
196 cmd.replace(QRegExp("([a-zA-Z]+)"), "Math.\\1"); //needed for accessing math funktions like sin(),....
198 QString result = calculate(cmd);
200 if (!result.isEmpty() && result != cmd) {
201 if (toHex) {
202 result = "0x" + QString::number(result.toInt(), 16).toUpper();
205 Plasma::QueryMatch match(this);
206 match.setType(Plasma::QueryMatch::InformationalMatch);
207 match.setIcon(KIcon("accessories-calculator"));
208 match.setText(result);
209 match.setData("= " + result);
210 match.setId(QString());
211 context.addMatch(term, match);
215 QString CalculatorRunner::calculate(const QString& term)
217 //kDebug() << "calculating" << term;
218 QScriptEngine eng;
219 QScriptValue result = eng.evaluate(term);
221 if (result.isError()) {
222 return QString();
225 return result.toString();
228 #include "calculatorrunner.moc"