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>
26 #include <QScriptEngine>
30 CalculatorRunner::CalculatorRunner( QObject
* parent
, const QVariantList
&args
)
31 : Plasma::AbstractRunner(parent
, 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;
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;
76 } else if (current
== '(') {
79 if (((next
<= '9' ) && (next
>= '0')) || next
== decimalSymbol
) {
90 //go forwards looking for the end of the number or expression
92 while (postIndex
!= cmd
.size() - 1) {
93 QChar current
=cmd
.at(postIndex
);
94 QChar next
=cmd
.at(postIndex
+ 1);
97 } else if (current
== ')') {
100 if (((next
<= '9' ) && (next
>= '0')) || next
== decimalSymbol
) {
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")) {
128 for (int i
= 0; i
< cmd
.size(); i
++) {
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
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();
172 //no meanless space between friendly guys: helps simplify code
173 cmd
= cmd
.trimmed().replace(" ", "");
175 if (cmd
.length() < 4) {
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('=')) {
187 // we don't have an actionable equation here
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
) {
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;
219 QScriptValue result
= eng
.evaluate(term
);
221 if (result
.isError()) {
225 return result
.toString();
228 #include "calculatorrunner.moc"