diff --git a/runners/converter/CMakeLists.txt b/runners/converter/CMakeLists.txt index 1771c2547..98297da31 100644 --- a/runners/converter/CMakeLists.txt +++ b/runners/converter/CMakeLists.txt @@ -1,23 +1,22 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_runner_converterrunner\") set(krunner_converter_SRCS converterrunner.cpp) -add_library(krunner_converter MODULE ${krunner_converter_SRCS}) -target_link_libraries(krunner_converter KF5::UnitConversion KF5::I18n KF5::Runner Qt5::Widgets) - -install(TARGETS krunner_converter DESTINATION ${KDE_INSTALL_PLUGINDIR}) -install(FILES plasma-runner-converter.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) - - -add_library(krunner_converter_test STATIC ${krunner_converter_SRCS}) -target_link_libraries(krunner_converter_test +add_library(krunner_converter_static STATIC ${krunner_converter_SRCS}) +target_link_libraries(krunner_converter_static KF5::I18n KF5::Runner KF5::UnitConversion Qt5::Widgets Qt5::Test ) +add_library(krunner_converter MODULE plugin.cpp) +target_link_libraries(krunner_converter krunner_converter_static) + +install(TARGETS krunner_converter DESTINATION ${KDE_INSTALL_PLUGINDIR}) +install(FILES plasma-runner-converter.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) + if(BUILD_TESTING) add_subdirectory(autotests) endif() diff --git a/runners/converter/autotests/CMakeLists.txt b/runners/converter/autotests/CMakeLists.txt index 44bfecab1..61608d6b1 100644 --- a/runners/converter/autotests/CMakeLists.txt +++ b/runners/converter/autotests/CMakeLists.txt @@ -1,5 +1,5 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII) include(ECMAddTests) -ecm_add_test(converterrunnertest.cpp TEST_NAME converterrunnertest LINK_LIBRARIES Qt5::Test krunner_converter_test) +ecm_add_test(converterrunnertest.cpp TEST_NAME converterrunnertest LINK_LIBRARIES Qt5::Test krunner_converter_static) diff --git a/runners/converter/converterrunner.cpp b/runners/converter/converterrunner.cpp index 50e48cf99..ebff7acf7 100644 --- a/runners/converter/converterrunner.cpp +++ b/runners/converter/converterrunner.cpp @@ -1,266 +1,261 @@ /* * Copyright (C) 2007,2008 Petri Damstén * Copyright (C) 2020 Alexander Lohnau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #include "converterrunner.h" #include #include #include #include #include #include -K_EXPORT_PLASMA_RUNNER(converterrunner, ConverterRunner) - ConverterRunner::ConverterRunner(QObject *parent, const QVariantList &args) : Plasma::AbstractRunner(parent, args) { setObjectName(QStringLiteral("Converter")); //can not ignore commands: we have things like m4 setIgnoredTypes(Plasma::RunnerContext::Directory | Plasma::RunnerContext::File | Plasma::RunnerContext::NetworkLocation); const QString description = i18n("Converts the value of :q: when :q: is made up of " "\"value unit [>, to, as, in] unit\". You can use the " "Unit converter applet to find all available units."); addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), description)); } void ConverterRunner::init() { valueRegex = QRegularExpression(QStringLiteral("^([0-9,./+-]+)")); const QStringList conversionWords = i18nc("list of words that can used as amount of 'unit1' [in|to|as] 'unit2'", "in;to;as").split(QLatin1Char(';')); QString conversionRegex; for (const auto &word: conversionWords) { conversionRegex.append(QLatin1Char(' ') + word + QStringLiteral(" |")); } conversionRegex.append(QStringLiteral(" ?> ?")); unitSeperatorRegex = QRegularExpression(conversionRegex); valueRegex.optimize(); unitSeperatorRegex.optimize(); insertCompatibleUnits(); addAction(copyActionId, QIcon::fromTheme(QStringLiteral("edit-copy")), QStringLiteral("Copy number")); addAction(copyUnitActionId, QIcon::fromTheme(QStringLiteral("edit-copy")), QStringLiteral("Copy unit and number")); actionList = {action(copyActionId), action(copyUnitActionId)}; } ConverterRunner::~ConverterRunner() = default; void ConverterRunner::match(Plasma::RunnerContext &context) { const QString term = context.query(); if (term.size() < 2 || !context.isValid()) { return; } const QRegularExpressionMatch valueRegexMatch = valueRegex.match(context.query()); if (!valueRegexMatch.hasMatch()) { return; } const QString inputValueString = valueRegexMatch.captured(1); // Get the different units by splitting up the query with the regex QStringList unitStrings = context.query().simplified().remove(valueRegex).split(unitSeperatorRegex); if (unitStrings.isEmpty()) { return; } // Check if unit is valid, otherwise check for the value in the compatibleUnits map QString inputUnitString = unitStrings.first().simplified(); KUnitConversion::UnitCategory inputCategory = converter.categoryForUnit(inputUnitString); if (inputCategory.id() == KUnitConversion::InvalidCategory) { inputUnitString = compatibleUnits.value(inputUnitString.toUpper()); if (inputUnitString.isEmpty()) { return; } inputCategory = converter.categoryForUnit(inputUnitString); if (inputCategory.id() == KUnitConversion::InvalidCategory) { return; } } QString outputUnitString; if (unitStrings.size() == 2) { outputUnitString = unitStrings.at(1).simplified(); } const KUnitConversion::Unit inputUnit = inputCategory.unit(inputUnitString); const QList outputUnits = createResultUnits(outputUnitString, inputCategory); const auto numberDataPair = getValidatedNumberValue(inputValueString); // Return on invalid user input if (!numberDataPair.first) { return; } const double numberValue = numberDataPair.second; QList matches; for (const KUnitConversion::Unit &outputUnit: outputUnits) { KUnitConversion::Value outputValue = inputCategory.convert( KUnitConversion::Value(numberValue, inputUnit), outputUnit); if (!outputValue.isValid() || inputUnit == outputUnit) { continue; } Plasma::QueryMatch match(this); match.setType(Plasma::QueryMatch::InformationalMatch); match.setIconName(QStringLiteral("accessories-calculator")); if (outputUnit.categoryId() == KUnitConversion::CurrencyCategory) { outputValue.round(2); match.setText(QStringLiteral("%1 (%2)").arg(outputValue.toString(0, 'f', 2), outputUnit.symbol())); } else { match.setText(QStringLiteral("%1 (%2)").arg(outputValue.toString(), outputUnit.symbol())); } match.setData(outputValue.number()); match.setRelevance(1.0 - std::abs(std::log10(outputValue.number())) / 50.0); matches.append(match); } context.addMatches(matches); } QList ConverterRunner::actionsForMatch(const Plasma::QueryMatch &match) { Q_UNUSED(match) return actionList; } void ConverterRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) { Q_UNUSED(context) if (match.selectedAction() == action(copyActionId)) { QGuiApplication::clipboard()->setText(match.data().toString()); } else { QGuiApplication::clipboard()->setText(match.text().split(QLatin1String(" (")).first()); } } QPair ConverterRunner::stringToDouble(const QStringRef &value) { bool ok; double numberValue = locale.toDouble(value, &ok); if (!ok) { numberValue = value.toDouble(&ok); } return {ok, numberValue}; } QPair ConverterRunner::getValidatedNumberValue(const QString &value) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) const auto fractionParts = value.splitRef(QLatin1Char('/'), QString::SkipEmptyParts); #else const auto fractionParts = value.splitRef(QLatin1Char('/'), Qt::SkipEmptyParts); #endif if (fractionParts.isEmpty() || fractionParts.count() > 2) { return {false, 0}; } if (fractionParts.count() == 2) { const QPair doubleFirstResults = stringToDouble(fractionParts.first()); if (!doubleFirstResults.first) { return {false, 0}; } const QPair doubleSecondResult = stringToDouble(fractionParts.last()); if (!doubleSecondResult.first || qFuzzyIsNull(doubleSecondResult.second)) { return {false, 0}; } return {true, doubleFirstResults.second / doubleSecondResult.second}; } else if (fractionParts.count() == 1) { const QPair doubleResult = stringToDouble(fractionParts.first()); if (!doubleResult.first) { return {false, 0}; } return {true, doubleResult.second}; } else { return {true, 0}; } } QList ConverterRunner::createResultUnits(QString &outputUnitString, const KUnitConversion::UnitCategory &category) { QList units; if (!outputUnitString.isEmpty()) { KUnitConversion::Unit outputUnit = category.unit(outputUnitString); if (!outputUnit.isNull() && outputUnit.isValid()) { units.append(outputUnit); } else { // Autocompletion for the target units outputUnitString = outputUnitString.toUpper(); for (const auto &unitStringKey: compatibleUnits.keys()) { if (unitStringKey.startsWith(outputUnitString)) { outputUnit = category.unit(compatibleUnits.value(unitStringKey)); if (!units.contains(outputUnit)) { units << outputUnit; } } } } } else { units = category.mostCommonUnits(); // suggest converting to the user's local currency if (category.id() == KUnitConversion::CurrencyCategory) { const QString ¤cyIsoCode = QLocale().currencySymbol(QLocale::CurrencyIsoCode); const KUnitConversion::Unit localCurrency = category.unit(currencyIsoCode); if (localCurrency.isValid() && !units.contains(localCurrency)) { units << localCurrency; } } } return units; } void ConverterRunner::insertCompatibleUnits() { // Add all currency symbols to the map, if their ISO code is supported by backend const QList allLocales = QLocale::matchingLocales( QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); KUnitConversion::UnitCategory currencyCategory = converter.category(QStringLiteral("Currency")); const QStringList availableISOCodes = currencyCategory.allUnits(); QRegularExpression hasCurrencyRegex = QRegularExpression(QStringLiteral("\\p{Sc}")); hasCurrencyRegex.optimize(); for (const auto ¤cyLocale: allLocales) { const QString symbol = currencyLocale.currencySymbol(QLocale::CurrencySymbol); const QString isoCode = currencyLocale.currencySymbol(QLocale::CurrencyIsoCode); if (isoCode.isEmpty() || !symbol.contains(hasCurrencyRegex)) { continue; } if (availableISOCodes.contains(isoCode)) { compatibleUnits.insert(symbol.toUpper(), isoCode); } } // Add all units as uppercase in the map for (const auto &category: converter.categories()) { for (const auto &unit: category.allUnits()) { compatibleUnits.insert(unit.toUpper(), unit); } } } - -#include "converterrunner.moc" diff --git a/runners/converter/plugin.cpp b/runners/converter/plugin.cpp new file mode 100644 index 000000000..f9c3611c3 --- /dev/null +++ b/runners/converter/plugin.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2007,2008 Petri Damstén + * Copyright (C) 2020 Alexander Lohnau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "converterrunner.h" + +K_EXPORT_PLASMA_RUNNER(converterrunner, ConverterRunner) + +#include "plugin.moc"