File indexing completed on 2024-04-28 03:40:31
0001 /*************************************************************************** 0002 * Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de * 0003 * (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "wordcompletion.h" 0022 0023 #include <QFile> 0024 #include <QList> 0025 #include <QRegularExpression> 0026 #include <QStandardPaths> 0027 #include <QTextStream> 0028 0029 #include <KConfigGroup> 0030 #include <KSharedConfig> 0031 0032 class WordCompletion::WordCompletionPrivate 0033 { 0034 friend class WordCompletion; 0035 0036 public: 0037 WordCompletionPrivate() 0038 : blockCurrentListSignal(false) 0039 , wordsToSave(false) 0040 { 0041 } 0042 0043 private: 0044 typedef QMap<QString, int> WordMap; 0045 struct DictionaryDetails { 0046 QString filename; 0047 QString language; 0048 }; 0049 0050 QString lastText; 0051 QMap<QString, int> map; 0052 QMap<QString, int> addedWords; 0053 QMap<QString, DictionaryDetails> dictDetails; 0054 QStringList dictionaries; 0055 QString current; 0056 bool blockCurrentListSignal; 0057 bool wordsToSave; 0058 }; 0059 0060 WordCompletion::WordCompletion() 0061 : KCompletion() 0062 { 0063 d = new WordCompletionPrivate(); 0064 configure(); 0065 } 0066 0067 WordCompletion::~WordCompletion() 0068 { 0069 save(); 0070 delete d; 0071 } 0072 0073 typedef QPair<int, QString> Match; 0074 typedef QList<Match> MatchList; 0075 0076 QString WordCompletion::makeCompletion(const QString &text) 0077 { 0078 if (d->lastText != text) { 0079 d->lastText = text; 0080 KCompletion::clear(); 0081 0082 int border = text.lastIndexOf(QRegularExpression(QStringLiteral("\\W"))); 0083 QString suffix = text.right(text.length() - border - 1).toLower(); 0084 QString prefix = text.left(border + 1); 0085 0086 if (suffix.length() > 0) { 0087 MatchList matches; 0088 QMap<QString, int>::ConstIterator it; 0089 for (it = d->map.constBegin(); it != d->map.constEnd(); ++it) 0090 if (it.key().startsWith(suffix)) 0091 matches += Match(-it.value(), it.key()); 0092 std::sort(matches.begin(), matches.end()); 0093 0094 MatchList::ConstIterator iter = matches.constBegin(); 0095 for (int count = 0; (iter != matches.constEnd()) && (count < 10); ++iter, ++count) { 0096 int length = (*iter).second.length() + prefix.length() - text.length(); 0097 KCompletion::addItem(text + (*iter).second.right(length), -(*iter).first); 0098 } 0099 } 0100 } 0101 0102 // call the KCompletion::makeCompletion(...) method 0103 return KCompletion::makeCompletion(text); 0104 } 0105 0106 QStringList WordCompletion::wordLists() 0107 { 0108 return d->dictionaries; 0109 } 0110 0111 QStringList WordCompletion::wordLists(const QString &language) 0112 { 0113 QStringList result; 0114 for (QStringList::const_iterator it = d->dictionaries.constBegin(); it != d->dictionaries.constEnd(); ++it) 0115 if (d->dictDetails[*it].language == language) 0116 result += *it; 0117 return result; 0118 } 0119 0120 QString WordCompletion::languageOfWordList(const QString &wordlist) 0121 { 0122 if (d->dictDetails.contains(wordlist)) 0123 return d->dictDetails[wordlist].language; 0124 else 0125 return QString(); 0126 } 0127 0128 QString WordCompletion::currentWordList() 0129 { 0130 return d->current; 0131 } 0132 0133 bool WordCompletion::isConfigured() 0134 { 0135 bool result = KSharedConfig::openConfig()->hasGroup(QLatin1String("Dictionary 0")); 0136 0137 return result; 0138 } 0139 0140 void WordCompletion::configure() 0141 { 0142 if (d->wordsToSave) 0143 save(); 0144 d->wordsToSave = false; 0145 0146 d->dictionaries.clear(); 0147 d->dictDetails.clear(); 0148 0149 const QStringList groups = KSharedConfig::openConfig()->groupList(); 0150 for (QStringList::const_iterator it = groups.constBegin(); it != groups.constEnd(); ++it) 0151 if ((*it).startsWith(QLatin1String("Dictionary "))) { 0152 KConfigGroup cg(KSharedConfig::openConfig(), *it); 0153 WordCompletionPrivate::DictionaryDetails details; 0154 details.filename = cg.readEntry("Filename"); 0155 details.language = cg.readEntry("Language"); 0156 QString name = cg.readEntry("Name"); 0157 d->dictDetails[name] = details; 0158 d->dictionaries += name; 0159 } 0160 0161 d->blockCurrentListSignal = true; 0162 setWordList(d->current); 0163 d->blockCurrentListSignal = false; 0164 Q_EMIT wordListsChanged(wordLists()); 0165 Q_EMIT currentListChanged(d->current); 0166 } 0167 0168 bool WordCompletion::setWordList(const QString &wordlist) 0169 { 0170 if (d->wordsToSave) 0171 save(); 0172 d->wordsToSave = false; 0173 0174 d->map.clear(); 0175 bool result = d->dictDetails.contains(wordlist); 0176 if (result) 0177 d->current = wordlist; 0178 else { 0179 if (d->dictionaries.isEmpty()) 0180 return false; 0181 d->current = d->dictionaries[0]; 0182 } 0183 0184 QString filename = d->dictDetails[d->current].filename; 0185 QString dictionaryFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, filename); 0186 QFile file(dictionaryFile); 0187 if (file.exists() && file.open(QIODevice::ReadOnly)) { 0188 QTextStream stream(&file); 0189 stream.setEncoding(QStringConverter::Utf8); 0190 if (!stream.atEnd()) { 0191 if (stream.readLine() == QLatin1String("WPDictFile")) { 0192 while (!stream.atEnd()) { 0193 QString s = stream.readLine(); 0194 if (!(s.isNull() || s.isEmpty())) { 0195 QStringList list = s.split(QLatin1Char('\t')); 0196 bool ok; 0197 int weight = list[1].toInt(&ok); 0198 if (ok && (weight > 0)) 0199 d->map[list[0]] = weight; 0200 } 0201 } 0202 } 0203 } 0204 file.close(); 0205 } 0206 if (!d->blockCurrentListSignal) 0207 Q_EMIT currentListChanged(d->current); 0208 d->lastText.clear(); 0209 d->wordsToSave = false; 0210 return result; 0211 } 0212 0213 void WordCompletion::addSentence(const QString &sentence) 0214 { 0215 const QStringList words = sentence.split(QRegularExpression(QStringLiteral("\\W"))); 0216 0217 QStringList::ConstIterator it; 0218 for (it = words.constBegin(); it != words.constEnd(); ++it) { 0219 if (!(*it).contains(QRegularExpression(QStringLiteral("\\d|_")))) { 0220 QString key = (*it).toLower(); 0221 if (d->map.contains(key)) 0222 d->map[key] += 1; 0223 else 0224 d->map[key] = 1; 0225 if (d->addedWords.contains(key)) 0226 d->addedWords[key] += 1; 0227 else 0228 d->addedWords[key] = 1; 0229 } 0230 } 0231 d->wordsToSave = true; 0232 } 0233 0234 void WordCompletion::save() 0235 { 0236 if (d->wordsToSave) { 0237 QString filename = d->dictDetails[d->current].filename; 0238 QString dictionaryFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, filename); 0239 QFile file(dictionaryFile); 0240 if (!file.exists()) 0241 return; 0242 if (!file.open(QIODevice::WriteOnly)) 0243 return; 0244 0245 QTextStream stream(&file); 0246 stream.setEncoding(QStringConverter::Utf8); 0247 stream << "WPDictFile\n"; 0248 QMap<QString, int>::ConstIterator it; 0249 for (it = d->map.constBegin(); it != d->map.constEnd(); ++it) { 0250 if (d->addedWords.contains(it.key())) { 0251 stream << it.key() << "\t" << d->addedWords[it.key()] << "\t1\n"; 0252 stream << it.key() << "\t" << it.value() - d->addedWords[it.key()] << "\t2\n"; 0253 } else 0254 stream << it.key() << "\t" << it.value() << "\t2\n"; 0255 } 0256 file.close(); 0257 d->wordsToSave = false; 0258 } 0259 }