Plasma
calculatorrunner.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "calculatorrunner.h"
00022
00023 #include <QScriptEngine>
00024
00025 #include <KIcon>
00026
00027 CalculatorRunner::CalculatorRunner( QObject* parent, const QVariantList &args )
00028 : Plasma::AbstractRunner(parent, args)
00029 {
00030 Q_UNUSED(args)
00031
00032 setObjectName("Calculator");
00033 setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File |
00034 Plasma::RunnerContext::NetworkLocation | Plasma::RunnerContext::Executable |
00035 Plasma::RunnerContext::ShellCommand);
00036
00037 QString description = i18n("Calculates the value of :q: when :q: is made up of numbers and "
00038 "mathematical symbols such as +, -, /, * and ^.");
00039 addSyntax(Plasma::RunnerSyntax("=:q:", description));
00040 addSyntax(Plasma::RunnerSyntax(":q:=", description));
00041 }
00042
00043 CalculatorRunner::~CalculatorRunner()
00044 {
00045 }
00046
00047 void CalculatorRunner::powSubstitutions(QString& cmd)
00048 {
00049 if (cmd.contains("e+", Qt::CaseInsensitive)) {
00050 cmd=cmd.replace("e+", "*10^", Qt::CaseInsensitive);
00051 }
00052
00053 if (cmd.contains("e-", Qt::CaseInsensitive)) {
00054 cmd=cmd.replace("e-", "*10^-", Qt::CaseInsensitive);
00055 }
00056
00057
00058
00059 if (cmd.contains('^')){
00060 int where = cmd.indexOf('^');
00061 cmd = cmd.replace('^', ',');
00062 int preIndex = where - 1;
00063 int postIndex = where + 1;
00064 int count = 0;
00065
00066 QChar decimalSymbol = KGlobal::locale()->decimalSymbol().at(0);
00067
00068 preIndex = qMax(0, preIndex);
00069 postIndex = qMin(postIndex, cmd.length()-1);
00070
00071
00072 while (preIndex != 0) {
00073 QChar current = cmd.at(preIndex);
00074 QChar next = cmd.at(preIndex-1);
00075
00076 if (current == ')') {
00077 count++;
00078 } else if (current == '(') {
00079 count--;
00080 } else {
00081 if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) {
00082 preIndex--;
00083 continue;
00084 }
00085 }
00086 if (count == 0) {
00087 break;
00088 }
00089 preIndex--;
00090 }
00091
00092
00093 count = 0;
00094 while (postIndex != cmd.size() - 1) {
00095 QChar current=cmd.at(postIndex);
00096 QChar next=cmd.at(postIndex + 1);
00097 if (current == '(') {
00098 count++;
00099 } else if (current == ')') {
00100 count--;
00101 } else {
00102 if (((next <= '9' ) && (next >= '0')) || next == decimalSymbol) {
00103 postIndex++;
00104 continue;
00105 }
00106 }
00107 if (count == 0) {
00108 break;
00109 }
00110 postIndex++;
00111 }
00112
00113 preIndex = qMax(0, preIndex);
00114 postIndex = qMin(postIndex, cmd.length());
00115
00116 cmd.insert(preIndex,"pow(");
00117
00118 cmd.insert(postIndex + 1 + 4, ')');
00119
00120 }
00121 }
00122
00123 void CalculatorRunner::hexSubstitutions(QString& cmd)
00124 {
00125 if (cmd.contains("0x")) {
00126 bool ok;
00127 int pos = 0;
00128 QString hex;
00129
00130 for (int i = 0; i < cmd.size(); i++) {
00131 hex.clear();
00132 pos = cmd.indexOf("0x", pos);
00133
00134 for (int q = 0; q < cmd.size(); q++) {
00135 QChar current = cmd[pos+q+2];
00136 if (((current <= '9' ) && (current >= '0')) || ((current <= 'F' ) && (current >= 'A'))) {
00137 hex[q] = current;
00138 } else {
00139 break;
00140 }
00141 }
00142 cmd = cmd.replace("0x" + hex,QString::number(hex.toInt(&ok,16)));
00143 }
00144 }
00145
00146 }
00147
00148 void CalculatorRunner::userFriendlySubstitutions(QString& cmd)
00149 {
00150 if (cmd.contains(KGlobal::locale()->decimalSymbol(), Qt::CaseInsensitive)) {
00151 cmd=cmd.replace(KGlobal::locale()->decimalSymbol(), ".", Qt::CaseInsensitive);
00152 }
00153
00154 hexSubstitutions(cmd);
00155 powSubstitutions(cmd);
00156
00157 if (cmd.contains(QRegExp("\\d+and\\d+"))) {
00158 cmd = cmd.replace(QRegExp("(\\d+)and(\\d+)"), "\\1&\\2");
00159 }
00160 if (cmd.contains(QRegExp("\\d+or\\d+"))) {
00161 cmd = cmd.replace(QRegExp("(\\d+)or(\\d+)"), "\\1|\\2");
00162 }
00163 if (cmd.contains(QRegExp("\\d+xor\\d+"))) {
00164 cmd = cmd.replace(QRegExp("(\\d+)xor(\\d+)"), "\\1^\\2");
00165 }
00166 }
00167
00168
00169 void CalculatorRunner::match(Plasma::RunnerContext &context)
00170 {
00171 const QString term = context.query();
00172 QString cmd = term;
00173
00174
00175 cmd = cmd.trimmed().replace(" ", "");
00176
00177 if (cmd.length() < 4) {
00178 return;
00179 }
00180 if (cmd.toLower() == "universe" || cmd.toLower() == "life") {
00181 Plasma::QueryMatch match(this);
00182 match.setType(Plasma::QueryMatch::InformationalMatch);
00183 match.setIcon(KIcon("accessories-calculator"));
00184 match.setText("= 42");
00185 match.setId(QString());
00186 context.addMatch(term, match);
00187 return;
00188 }
00189
00190 bool toHex = cmd.startsWith("hex=");
00191 bool startsWithEquals = !toHex && cmd[0] == '=';
00192
00193 if (toHex || startsWithEquals) {
00194 cmd.remove(0, cmd.indexOf('=') + 1);
00195 } else if (cmd.endsWith('=')) {
00196 cmd.chop(1);
00197 } else {
00198
00199 return;
00200 }
00201
00202 if (cmd.isEmpty()) {
00203 return;
00204 }
00205
00206 userFriendlySubstitutions(cmd);
00207 cmd.replace(QRegExp("([a-zA-Z]+)"), "Math.\\1");
00208
00209 QString result = calculate(cmd);
00210
00211 if (!result.isEmpty() && result != cmd) {
00212 if (toHex) {
00213 result = "0x" + QString::number(result.toInt(), 16).toUpper();
00214 }
00215
00216 Plasma::QueryMatch match(this);
00217 match.setType(Plasma::QueryMatch::InformationalMatch);
00218 match.setIcon(KIcon("accessories-calculator"));
00219 match.setText(result);
00220 match.setData("= " + result);
00221 match.setId(QString());
00222 context.addMatch(term, match);
00223 }
00224 }
00225
00226 QString CalculatorRunner::calculate(const QString& term)
00227 {
00228
00229 QScriptEngine eng;
00230 QScriptValue result = eng.evaluate(term);
00231
00232 if (result.isError()) {
00233 return QString();
00234 }
00235
00236 return result.toString();
00237 }
00238
00239 #include "calculatorrunner.moc"