diff --git a/src/core/loader.cpp b/src/core/loader.cpp index 13c5c25..e9ea487 100644 --- a/src/core/loader.cpp +++ b/src/core/loader.cpp @@ -1,361 +1,360 @@ /** * * Copyright (C) 2003 Zack Rusin * Copyright (C) 2012 Martin Sandsmark * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include "loader_p.h" #include "settings_p.h" #include "client_p.h" #include "spellerplugin_p.h" #include #include #include #include #include #include "core_debug.h" #include #include #ifdef SONNET_STATIC #include "../plugins/hunspell/hunspellclient.h" #ifdef Q_OS_MACOS #include "../plugins/nsspellchecker/nsspellcheckerclient.h" #endif #endif namespace Sonnet { class LoaderPrivate { public: Settings *settings; // QMap > languageClients; QStringList clients; QStringList languagesNameCache; QHash > spellerCache; }; Q_GLOBAL_STATIC(Loader, s_loader) Loader *Loader::openLoader() { if (s_loader.isDestroyed()) { return nullptr; } return s_loader(); } Loader::Loader() : d(new LoaderPrivate) { d->settings = new Settings(this); d->settings->restore(); loadPlugins(); } Loader::~Loader() { qCDebug(SONNET_LOG_CORE) << "Removing loader: " << this; delete d->settings; d->settings = nullptr; delete d; } SpellerPlugin *Loader::createSpeller(const QString &language, const QString &clientName) const { QString backend = clientName; QString plang = language; if (plang.isEmpty()) { plang = d->settings->defaultLanguage(); } const QVector lClients = d->languageClients[plang]; if (lClients.isEmpty()) { qCWarning(SONNET_LOG_CORE) << "No language dictionaries for the language:" << plang; return nullptr; } if (backend.isEmpty()) { backend = d->settings->defaultClient(); if (!backend.isEmpty()) { // check if the default client supports the requested language; // if it does it will be an element of lClients. bool unknown = !std::any_of(lClients.constBegin(), lClients.constEnd(), [backend] (const Client *client) { return client->name() == backend; }); if (unknown) { qCWarning(SONNET_LOG_CORE) << "Default client" << backend << "doesn't support language:" << plang; backend = QString(); } } } QVectorIterator itr(lClients); while (itr.hasNext()) { Client *item = itr.next(); if (!backend.isEmpty()) { if (backend == item->name()) { SpellerPlugin *dict = item->createSpeller(plang); qCDebug(SONNET_LOG_CORE) << "Using the" << item->name() << "plugin for language" << plang; return dict; } } else { //the first one is the one with the highest //reliability SpellerPlugin *dict = item->createSpeller(plang); qCDebug(SONNET_LOG_CORE) << "Using the" << item->name() << "plugin for language" << plang; return dict; } } qCWarning(SONNET_LOG_CORE) << "The default client" << backend << "has no language dictionaries for the language:" << plang; return nullptr; } QSharedPointer Loader::cachedSpeller(const QString &language) { auto &speller = d->spellerCache[language]; if (!speller) { speller.reset(createSpeller(language)); } return speller; } void Loader::clearSpellerCache() { d->spellerCache.clear(); } QStringList Loader::clients() const { return d->clients; } QStringList Loader::languages() const { return d->languageClients.keys(); } QString Loader::languageNameForCode(const QString &langCode) const { QString currentDictionary = langCode, // e.g. en_GB-ize-wo_accents isoCode, // locale ISO name variantName, // dictionary variant name e.g. w_accents localizedLang, // localized language localizedCountry, // localized country localizedVariant; QByteArray variantEnglish; // dictionary variant in English int minusPos, // position of "-" char variantCount = 0; // used to iterate over variantList struct variantListType { const char *variantShortName; const char *variantEnglishName; }; /* * This redefines the QT_TRANSLATE_NOOP3 macro provided by Qt to indicate that * statically initialised text should be translated so that it expands to just * the string that should be translated, making it possible to use it in the * single string construct below. */ #undef QT_TRANSLATE_NOOP3 #define QT_TRANSLATE_NOOP3(a, b, c) b const variantListType variantList[] = { { "40", QT_TRANSLATE_NOOP3("Sonnet::Loader", "40", "dictionary variant") }, // what does 40 mean? { "60", QT_TRANSLATE_NOOP3("Sonnet::Loader", "60", "dictionary variant") }, // what does 60 mean? { "80", QT_TRANSLATE_NOOP3("Sonnet::Loader", "80", "dictionary variant") }, // what does 80 mean? { "ise", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ise suffixes", "dictionary variant") }, { "ize", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ize suffixes", "dictionary variant") }, { "ise-w_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ise suffixes and with accents", "dictionary variant") }, { "ise-wo_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ise suffixes and without accents", "dictionary variant") }, { "ize-w_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ize suffixes and with accents", "dictionary variant") }, { "ize-wo_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "-ize suffixes and without accents", "dictionary variant") }, { "lrg", QT_TRANSLATE_NOOP3("Sonnet::Loader", "large", "dictionary variant") }, { "med", QT_TRANSLATE_NOOP3("Sonnet::Loader", "medium", "dictionary variant") }, { "sml", QT_TRANSLATE_NOOP3("Sonnet::Loader", "small", "dictionary variant") }, { "variant_0", QT_TRANSLATE_NOOP3("Sonnet::Loader", "variant 0", "dictionary variant") }, { "variant_1", QT_TRANSLATE_NOOP3("Sonnet::Loader", "variant 1", "dictionary variant") }, { "variant_2", QT_TRANSLATE_NOOP3("Sonnet::Loader", "variant 2", "dictionary variant") }, { "wo_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "without accents", "dictionary variant") }, { "w_accents", QT_TRANSLATE_NOOP3("Sonnet::Loader", "with accents", "dictionary variant") }, { "ye", QT_TRANSLATE_NOOP3("Sonnet::Loader", "with ye, modern russian", "dictionary variant") }, { "yeyo", QT_TRANSLATE_NOOP3("Sonnet::Loader", "with yeyo, modern and old russian", "dictionary variant") }, { "yo", QT_TRANSLATE_NOOP3("Sonnet::Loader", "with yo, old russian", "dictionary variant") }, { "extended", QT_TRANSLATE_NOOP3("Sonnet::Loader", "extended", "dictionary variant") }, { nullptr, nullptr } }; minusPos = currentDictionary.indexOf(QLatin1Char('-')); if (minusPos != -1) { variantName = currentDictionary.right(currentDictionary.length() - minusPos - 1); while (variantList[variantCount].variantShortName != nullptr) { if (QLatin1String(variantList[variantCount].variantShortName) == variantName) { break; } else { variantCount++; } } if (variantList[variantCount].variantShortName != nullptr) { variantEnglish = variantList[variantCount].variantEnglishName; } else { variantEnglish = variantName.toLatin1(); } localizedVariant = tr(variantEnglish.constData(), "dictionary variant"); isoCode = currentDictionary.left(minusPos); } else { isoCode = currentDictionary; } QLocale locale(isoCode); localizedCountry = locale.nativeCountryName(); localizedLang = locale.nativeLanguageName(); if (localizedLang.isEmpty() && localizedCountry.isEmpty()) { return isoCode; // We have nothing } if (!localizedCountry.isEmpty() && !localizedVariant.isEmpty()) { // We have both a country name and a variant return tr("%1 (%2) [%3]", "dictionary name; %1 = language name, %2 = country name and %3 = language variant name" ).arg(localizedLang, localizedCountry, localizedVariant); } else if (!localizedCountry.isEmpty()) { // We have a country name return tr("%1 (%2)", "dictionary name; %1 = language name, %2 = country name" ).arg(localizedLang, localizedCountry); } else { // We only have a language name return localizedLang; } } QStringList Loader::languageNames() const { /* For whatever reason languages() might change. So, * to be in sync with it let's do the following check. */ if (d->languagesNameCache.count() == languages().count()) { return d->languagesNameCache; } QStringList allLocalizedDictionaries; - Q_FOREACH (const QString &langCode, languages()) { + for (const QString &langCode : languages()) { allLocalizedDictionaries.append(languageNameForCode(langCode)); } // cache the list d->languagesNameCache = allLocalizedDictionaries; return allLocalizedDictionaries; } Settings *Loader::settings() const { return d->settings; } void Loader::loadPlugins() { #ifndef SONNET_STATIC - const QStringList libPaths = QCoreApplication::libraryPaths() << QStringLiteral( - INSTALLATION_PLUGIN_PATH); + const QStringList libPaths = QCoreApplication::libraryPaths() << QStringLiteral(INSTALLATION_PLUGIN_PATH); const QLatin1String pathSuffix("/kf5/sonnet/"); int plugins = 0; - Q_FOREACH (const QString &libPath, libPaths) { + for (const QString &libPath : libPaths) { QDir dir(libPath + pathSuffix); if (!dir.exists()) { continue; } - Q_FOREACH (const QString &fileName, dir.entryList(QDir::Files)) { + for (const QString &fileName : dir.entryList(QDir::Files)) { loadPlugin(dir.absoluteFilePath(fileName)); plugins++; } } if (plugins == 0) { qCWarning(SONNET_LOG_CORE) << "Sonnet: No speller backends available!"; } #else #ifdef Q_OS_MACOS loadPlugin(QString()); #endif loadPlugin(QStringLiteral("Hunspell")); #endif } void Loader::loadPlugin(const QString &pluginPath) { #ifndef SONNET_STATIC QPluginLoader plugin(pluginPath); if (!plugin.load()) { // We do this separately for better error handling qCWarning(SONNET_LOG_CORE) << "Sonnet: Unable to load plugin" << pluginPath << "Error:" << plugin.errorString(); return; } Client *client = qobject_cast(plugin.instance()); if (!client) { qCWarning(SONNET_LOG_CORE) << "Sonnet: Invalid plugin loaded" << pluginPath; plugin.unload(); // don't leave it in memory return; } #else Client *client = nullptr; if (pluginPath == QLatin1String("Hunspell")) { client = new HunspellClient(this); } #ifdef Q_OS_MACOS else { client = new NSSpellCheckerClient(this); } #endif #endif const QStringList languages = client->languages(); d->clients.append(client->name()); - Q_FOREACH (const QString &language, languages) { + for (const QString &language : languages) { QVector &languageClients = d->languageClients[language]; if (languageClients.isEmpty() || client->reliability() < languageClients.first()->reliability()) { languageClients.append(client); // less reliable, to the end } else { languageClients.prepend(client); // more reliable, to the front } } } void Loader::changed() { emit configurationChanged(); } }