File indexing completed on 2024-05-19 05:01:19
0001 /* 0002 This file is part of the KDE project. 0003 0004 SPDX-FileCopyrightText: 2021 Stefano Crocco <posta@stefanocrocco.it> 0005 0006 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 #include "spellcheckermanager.h" 0010 #include "webenginepage.h" 0011 0012 #include <QDir> 0013 #include <QStringList> 0014 #include <QDebug> 0015 #include <QWebEngineProfile> 0016 #include <QMenu> 0017 #include <QAction> 0018 #include <QLibraryInfo> 0019 #include <QApplication> 0020 0021 #include <KActionCollection> 0022 #include <KLocalizedString> 0023 #include <KSharedConfig> 0024 #include <KConfigGroup> 0025 0026 #include <konq_spellcheckingconfigurationdispatcher.h> 0027 0028 QString SpellCheckerManager::dictionaryDir() 0029 { 0030 static const char *varName = "QTWEBENGINE_DICTIONARIES_PATH"; 0031 static QString s_dir; 0032 if (s_dir.isNull()) { 0033 if (qEnvironmentVariableIsSet(varName)) { 0034 s_dir = qEnvironmentVariable(varName); 0035 } else { 0036 #ifdef WEBENGINEPART_OWN_DICTIONARY_DIR 0037 s_dir = QString(WEBENGINEPART_OWN_DICTIONARY_DIR); 0038 #else 0039 QLatin1String suffix("/qtwebengine_dictionaries"); 0040 s_dir = QApplication::applicationDirPath() + suffix; 0041 if (!QDir(s_dir).exists()) { 0042 s_dir = QLibraryInfo::location(QLibraryInfo::DataPath) + suffix; 0043 } 0044 #endif 0045 } 0046 } 0047 return s_dir; 0048 } 0049 0050 SpellCheckerManager::SpellCheckerManager(QWebEngineProfile *profile, QObject *parent): QObject(parent), m_profile(profile) 0051 { 0052 m_dictionaryDir = dictionaryDir(); 0053 connect(KonqSpellCheckingConfigurationDispatcher::self(), &KonqSpellCheckingConfigurationDispatcher::spellCheckingConfigurationChanged, 0054 this, &SpellCheckerManager::updateConfiguration); 0055 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0056 KConfigGroup grp = cfg->group("General"); 0057 updateConfiguration(grp.readEntry("SpellCheckingEnabled", false)); 0058 } 0059 0060 SpellCheckerManager::~SpellCheckerManager() 0061 { 0062 } 0063 0064 void SpellCheckerManager::detectDictionaries() 0065 { 0066 if (m_dictionaryDir.isEmpty()) { 0067 m_dicts.clear(); 0068 m_enabledDicts.clear(); 0069 return; 0070 } 0071 QStringList files = QDir(m_dictionaryDir).entryList({"*.bdic"}); 0072 QStringList languages; 0073 std::transform(files.constBegin(), files.constEnd(), std::back_inserter(languages), [](const QString &f){return f.chopped(5);}); 0074 QMap<QString, QString> dicts = m_speller.availableDictionaries(); 0075 for (auto it = dicts.constBegin(); it != dicts.constEnd(); ++it) { 0076 if (languages.contains(it.value())) { 0077 m_dicts[it.value()] = it.key(); 0078 } 0079 } 0080 QMap<QString, QString> preferred = m_speller.preferredDictionaries(); 0081 for (auto it = preferred.constBegin(); it != preferred.constEnd(); ++it) { 0082 if (m_dicts.contains(it.value())) { 0083 m_enabledDicts << it.value(); 0084 } 0085 } 0086 } 0087 0088 void SpellCheckerManager::updateConfiguration(bool spellCheckingEnabled) 0089 { 0090 detectDictionaries(); 0091 m_profile->setSpellCheckEnabled(spellCheckingEnabled); 0092 m_profile->setSpellCheckLanguages(m_enabledDicts); 0093 } 0094 0095 QMenu * SpellCheckerManager::spellCheckingMenu(const QStringList &suggestions, KActionCollection* coll, WebEnginePage* page) 0096 { 0097 QMenu *menu = new QMenu(); 0098 menu->setTitle(i18n("Spelling")); 0099 0100 bool spellingEnabled = m_profile->isSpellCheckEnabled(); 0101 0102 QAction *a = new QAction(i18n("Spell Checking Enabled"), coll); 0103 a->setCheckable(true); 0104 a->setChecked(spellingEnabled); 0105 connect(a, &QAction::toggled, this, &SpellCheckerManager::spellCheckingToggled); 0106 menu->addAction(a); 0107 0108 if (spellingEnabled) { 0109 if (!suggestions.isEmpty()) { 0110 menu->addSeparator(); 0111 for (const QString &s : suggestions) { 0112 a = new QAction(s, menu); 0113 menu->addAction(a); 0114 connect(a, &QAction::triggered, page, [page, s](){page->replaceMisspelledWord(s);}); 0115 } 0116 } 0117 0118 menu->addSeparator(); 0119 QMenu *langs = new QMenu(menu); 0120 langs->setTitle(i18n("&Languages")); 0121 menu->addMenu(langs); 0122 QStringList enabledLangs = m_profile->spellCheckLanguages(); 0123 for (auto it = m_dicts.constBegin(); it != m_dicts.constEnd(); ++it) { 0124 a = new QAction(it.value(), coll); 0125 a->setCheckable(true); 0126 const QString lang = it.key(); 0127 a->setChecked(enabledLangs.contains(lang)); 0128 connect(a, &QAction::toggled, this, [this, lang](bool on){on ? addLanguage(lang) : removeLanguage(lang);}); 0129 langs->addAction(a); 0130 } 0131 0132 } 0133 return menu; 0134 } 0135 0136 void SpellCheckerManager::addLanguage(const QString& lang) 0137 { 0138 QStringList langs = m_profile->spellCheckLanguages(); 0139 if (!langs.contains(lang)) { 0140 langs << lang; 0141 m_profile->setSpellCheckLanguages(langs); 0142 } 0143 } 0144 0145 void SpellCheckerManager::removeLanguage(const QString& lang) 0146 { 0147 QStringList langs = m_profile->spellCheckLanguages(); 0148 langs.removeAll(lang); 0149 m_profile->setSpellCheckLanguages(langs); 0150 } 0151 0152 void SpellCheckerManager::spellCheckingToggled(bool on) 0153 { 0154 m_profile->setSpellCheckEnabled(on); 0155 }