3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-19 05:35:53 +00:00
Brooklyn/plasma/workspace/runners/calculator/calculatorrunner.cpp
2022-03-05 22:41:29 +05:00

193 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
SPDX-FileCopyrightText: 2007 Barış Metin <baris@pardus.org.tr>
SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
SPDX-FileCopyrightText: 2007 Richard Moore <rich@kde.org>
SPDX-FileCopyrightText: 2010 Matteo Agostinelli <agostinelli@gmail.com>
SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.0-only
*/
#include "calculatorrunner.h"
#include "qalculate_engine.h"
#include <QDebug>
#include <QIcon>
#include <QMutex>
#include <QRegularExpression>
#include <KLocalizedString>
#include <krunner/querymatch.h>
K_PLUGIN_CLASS_WITH_JSON(CalculatorRunner, "plasma-runner-calculator.json")
static QMutex s_initMutex;
CalculatorRunner::CalculatorRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
: Plasma::AbstractRunner(parent, metaData, args)
{
setObjectName(QStringLiteral("Calculator"));
QString description = i18n(
"Calculates the value of :q: when :q: is made up of numbers and "
"mathematical symbols such as +, -, /, *, ! and ^.");
addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), description));
addSyntax(Plasma::RunnerSyntax(QStringLiteral("=:q:"), description));
addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:="), description));
m_actions = {new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy to Clipboard"), this)};
setMinLetterCount(2);
}
CalculatorRunner::~CalculatorRunner()
{
}
void CalculatorRunner::userFriendlySubstitutions(QString &cmd)
{
if (QLocale().decimalPoint() != QLatin1Char('.')) {
cmd.replace(QLocale().decimalPoint(), QLatin1Char('.'), Qt::CaseInsensitive);
} else if (!cmd.contains(QLatin1Char('[')) && !cmd.contains(QLatin1Char(']'))) {
// If we are sure that the user does not want to use vectors we can replace this char
// Especially when switching between locales that use a different decimal separator
// this ensures that the results are valid, see BUG: 406388
cmd.replace(QLatin1Char(','), QLatin1Char('.'), Qt::CaseInsensitive);
}
}
void CalculatorRunner::match(Plasma::RunnerContext &context)
{
const QString term = context.query();
QString cmd = term;
// no meanless space between friendly guys: helps simplify code
cmd = cmd.trimmed().remove(QLatin1Char(' '));
if (cmd.length() < 2) {
return;
}
if (cmd.toLower() == QLatin1String("universe") || cmd.toLower() == QLatin1String("life")) {
Plasma::QueryMatch match(this);
match.setType(Plasma::QueryMatch::InformationalMatch);
match.setIconName(QStringLiteral("accessories-calculator"));
match.setText(QStringLiteral("42"));
match.setData(QStringLiteral("42"));
match.setId(term);
context.addMatch(match);
return;
}
bool toHex = cmd.startsWith(QLatin1String("hex="));
bool startsWithEquals = !toHex && cmd[0] == QLatin1Char('=');
const static QRegularExpression hexRegex(QStringLiteral("0x[0-9a-f]+"), QRegularExpression::CaseInsensitiveOption);
const bool parseHex = cmd.contains(hexRegex);
if (!parseHex) {
userFriendlyMultiplication(cmd);
}
if (toHex || startsWithEquals) {
cmd.remove(0, cmd.indexOf(QLatin1Char('=')) + 1);
} else if (cmd.endsWith(QLatin1Char('='))) {
cmd.chop(1);
} else if (!parseHex) {
bool foundDigit = false;
for (int i = 0; i < cmd.length(); ++i) {
QChar c = cmd.at(i);
if (c.isLetter() && c != QLatin1Char('!')) {
// not just numbers and symbols, so we return
return;
}
if (c.isDigit()) {
foundDigit = true;
}
}
if (!foundDigit) {
return;
}
}
if (cmd.isEmpty()) {
return;
}
userFriendlySubstitutions(cmd);
bool isApproximate = false;
QString result = calculate(cmd, &isApproximate);
if (!result.isEmpty() && (result != cmd || toHex)) {
if (toHex) {
result = QLatin1String("0x") + QString::number(result.toInt(), 16).toUpper();
}
Plasma::QueryMatch match(this);
match.setType(Plasma::QueryMatch::InformationalMatch);
match.setIconName(QStringLiteral("accessories-calculator"));
match.setText(result);
if (isApproximate) {
match.setSubtext(i18nc("The result of the calculation is only an approximation", "Approximation"));
}
match.setData(result);
match.setId(term);
match.setActions(m_actions);
context.addMatch(match);
}
}
QString CalculatorRunner::calculate(const QString &term, bool *isApproximate)
{
{
QMutexLocker lock(&s_initMutex);
if (!m_engine) {
m_engine = std::make_unique<QalculateEngine>();
}
}
QString result;
try {
result = m_engine->evaluate(term, isApproximate);
} catch (std::exception &e) {
qDebug() << "qalculate error: " << e.what();
}
return result.replace(QLatin1Char('.'), QLocale().decimalPoint(), Qt::CaseInsensitive);
}
void CalculatorRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match)
{
Q_UNUSED(context)
if (match.selectedAction()) {
m_engine->copyToClipboard();
}
}
QMimeData *CalculatorRunner::mimeDataForMatch(const Plasma::QueryMatch &match)
{
QMimeData *result = new QMimeData();
result->setText(match.text());
return result;
}
void CalculatorRunner::userFriendlyMultiplication(QString &cmd)
{
// convert multiplication sign to *
cmd.replace(QChar(U'\u00D7'), QChar('*'));
for (int i = 0; i < cmd.length(); ++i) {
if (i == 0 || i == cmd.length() - 1) {
continue;
}
const QChar prev = cmd.at(i - 1);
const QChar current = cmd.at(i);
const QChar next = cmd.at(i + 1);
if (current == QLatin1Char('x')) {
if (prev.isDigit() && (next.isDigit() || next == QLatin1Char(',') || next == QLatin1Char('.'))) {
cmd[i] = '*';
}
}
}
}
#include "calculatorrunner.moc"