• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

calculatorrunner.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright (C) 2007 Barış Metin <baris@pardus.org.tr>
00003  *   Copyright (C) 2006 David Faure <faure@kde.org>
00004  *   Copyright (C) 2007 Richard Moore <rich@kde.org>
00005  *
00006  *   This program is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU Library General Public License version 2 as
00008  *   published by the Free Software Foundation
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
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     // the below code is scary mainly because we have to honor priority
00058    // honor decimal numbers and parenthesis.
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         //avoid out of range on weird commands
00068         preIndex = qMax(0, preIndex);
00069         postIndex = qMin(postIndex, cmd.length()-1);
00070 
00071         //go backwards looking for the beginning of the number or expression
00072         while (preIndex != 0) {
00073             QChar current = cmd.at(preIndex);
00074             QChar next = cmd.at(preIndex-1);
00075             //kDebug() << "index " << preIndex << " char " << current;
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        //go forwards looking for the end of the number or expression
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         // +1 +4 == next position to the last number after we add 4 new characters pow(
00118         cmd.insert(postIndex + 1 + 4, ')');
00119         //kDebug() << "from" << preIndex << " to " << postIndex << " got: " << cmd;
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++) {//find end of hex number
00135                 QChar current = cmd[pos+q+2];
00136                 if (((current <= '9' ) && (current >= '0')) || ((current <= 'F' ) && (current >= 'A'))) { //Check if valid hex sign
00137                     hex[q] = current;
00138                 } else {
00139                     break;
00140                 }
00141             }
00142             cmd = cmd.replace("0x" + hex,QString::number(hex.toInt(&ok,16))); //replace hex with decimal
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     //no meanless space between friendly guys: helps simplify code
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         // we don't have an actionable equation here
00199         return;
00200     }
00201 
00202     if (cmd.isEmpty()) {
00203         return;
00204     }
00205 
00206     userFriendlySubstitutions(cmd);
00207     cmd.replace(QRegExp("([a-zA-Z]+)"), "Math.\\1"); //needed for accessing math funktions like sin(),....
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     //kDebug() << "calculating" << term;
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"

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •     Animators
  •     Applets
  •     Engines
  • Solid Modules
  • System Settings
  •   SystemSettingsView
Generated for API Reference by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal