File indexing completed on 2024-12-08 06:28:22
0001 /* 0002 This file is part of Kiten, a KDE Japanese Reference Tool 0003 SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com> 0004 SPDX-FileCopyrightText: 2011 Daniel E. Moctezuma <democtezuma@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "dictionarymanager.h" 0010 0011 #include "dictfile.h" 0012 #include "dictionarypreferencedialog.h" 0013 #include "dictquery.h" 0014 #include "entry.h" 0015 #include "entrylist.h" 0016 #include "kitenmacros.h" 0017 0018 #include <KConfig> 0019 #include <KConfigSkeleton> 0020 0021 #include <QString> 0022 0023 /* Includes to handle various types of dictionaries 0024 IMPORTANT: To add a dictionary type, add the header file here and add it to the 0025 if statement under addDictionary() */ 0026 #include "DictEdict/dictfileedict.h" 0027 #include "DictKanjidic/dictfilekanjidic.h" 0028 0029 using namespace Qt::StringLiterals; 0030 0031 class DictionaryManager::Private 0032 { 0033 public: 0034 /** 0035 * List of dictionaries, indexed by name 0036 */ 0037 QHash<QString, DictFile *> dictManagers; 0038 }; 0039 0040 #if 0 0041 class debug_entry : public Entry 0042 { 0043 public: 0044 debug_entry(QString word) : Entry( QString( "libkiten" ), word 0045 , QStringList(), QStringList() ), count( counter++ ) 0046 { } 0047 virtual Entry * clone() const { return new debug_entry( *this ); } 0048 virtual bool loadEntry( const QString& ) { return false; } 0049 virtual QString dumpEntry() const { return ""; } 0050 virtual bool sort( const debug_entry &that, const QStringList &dicts, 0051 const QStringList &fields ) 0052 { return this->count < that.count; } 0053 0054 int count; 0055 static int counter; 0056 }; 0057 int debug_entry::counter = 0; 0058 #endif 0059 0060 /** 0061 * The constructor. Set autodelete on our dictionary list 0062 */ 0063 DictionaryManager::DictionaryManager() 0064 : d(new Private) 0065 { 0066 } 0067 0068 /** 0069 * Delete everything in our hash 0070 */ 0071 DictionaryManager::~DictionaryManager() 0072 { 0073 { 0074 QMutableHashIterator<QString, DictFile *> it(d->dictManagers); 0075 while (it.hasNext()) { 0076 it.next(); 0077 delete it.value(); 0078 it.remove(); 0079 } 0080 } 0081 0082 delete d; 0083 } 0084 0085 /** 0086 * Given a named Dict file/name/type... create and add the object if it 0087 * seems to work properly on creation. 0088 */ 0089 bool DictionaryManager::addDictionary(const QString &file, const QString &name, const QString &type) 0090 { 0091 if (d->dictManagers.contains(name)) // This name already exists in the list! 0092 { 0093 return false; 0094 } 0095 0096 DictFile *newDict = makeDictFile(type); 0097 if (newDict == nullptr) { 0098 return false; 0099 } 0100 0101 if (!newDict->loadDictionary(file, name)) { 0102 qDebug() << "Dictionary load FAILED: " << newDict->getName(); 0103 delete newDict; 0104 return false; 0105 } 0106 0107 qDebug() << "Dictionary Loaded : " << newDict->getName(); 0108 d->dictManagers.insert(name, newDict); 0109 return true; 0110 } 0111 0112 /** 0113 * Examine the DictQuery and farm out the search to the specialized dict 0114 * managers. Note that a global search limit will probably be implemented 0115 * either here or in the DictFile implementations... probably both 0116 * 0117 * @param query the query, see DictQuery documentation 0118 */ 0119 EntryList *DictionaryManager::doSearch(const DictQuery &query) const 0120 { 0121 auto ret = new EntryList(); 0122 #if 0 0123 if( query.getMeaning() == "(libkiten)" ) 0124 { 0125 ret->append( new debug_entry( "Summary of libkiten data" ) ); 0126 foreach( const QString &dict, listDictionaries() ) 0127 { 0128 ret->append( new debug_entry( dict ) ); 0129 } 0130 return ret; 0131 } 0132 #endif 0133 0134 // There are two basic modes.... one in which the query 0135 // specifies the dictionary list, one in which it does not 0136 QStringList dictsFromQuery = query.getDictionaries(); 0137 if (dictsFromQuery.isEmpty()) { 0138 // None specified, search all 0139 for (DictFile *it : d->dictManagers) { 0140 qDebug() << "Searching in " << it->getName() << "dictionary."; 0141 EntryList *temp = it->doSearch(query); 0142 if (temp) { 0143 ret->appendList(temp); 0144 } 0145 delete temp; 0146 } 0147 } else { 0148 for (const QString &target : dictsFromQuery) { 0149 DictFile *newestFound = d->dictManagers.find(target).value(); 0150 if (newestFound != nullptr) { 0151 EntryList *temp = newestFound->doSearch(query); 0152 if (temp) { 0153 ret->appendList(temp); 0154 } 0155 delete temp; 0156 } 0157 } 0158 } 0159 0160 ret->setQuery(query); // Store the query for later use. 0161 qDebug() << "From query: '" << query.toString() << "' Found " << ret->count() << " results"; 0162 qDebug() << "Incoming match type: " << query.getMatchType() << " Outgoing: " << ret->getQuery().getMatchType(); 0163 return ret; 0164 } 0165 0166 /** 0167 * For this case, we let polymorphism do most of the work. We assume that the user wants 0168 * to pare down the results, so we let the individual entry matching methods run over the 0169 * new query and accept (and copy) any of those that pass. 0170 */ 0171 EntryList *DictionaryManager::doSearchInList(const DictQuery &query, const EntryList *list) const 0172 { 0173 auto ret = new EntryList(); 0174 0175 for (Entry *it : *list) { 0176 if (it->matchesQuery(query)) { 0177 Entry *x = it->clone(); 0178 ret->append(x); 0179 } 0180 } 0181 0182 ret->setQuery(query + list->getQuery()); 0183 return ret; 0184 } 0185 0186 QMap<QString, QString> DictionaryManager::generateExtendedFieldsList() 0187 { 0188 QMap<QString, QString> result; 0189 const QStringList dictTypes = listDictFileTypes(); 0190 for (const QString &dictType : dictTypes) { 0191 DictFile *tempDictFile = makeDictFile(dictType); 0192 QMap<QString, QString> tempList = tempDictFile->getSearchableAttributes(); 0193 QMap<QString, QString>::const_iterator it = tempList.constBegin(); 0194 while (it != tempList.constEnd()) { 0195 if (!result.contains(it.key())) { 0196 result.insert(it.key(), it.value()); 0197 } 0198 ++it; 0199 } 0200 delete tempDictFile; 0201 } 0202 0203 return result; 0204 } 0205 0206 QMap<QString, DictionaryPreferenceDialog *> DictionaryManager::generatePreferenceDialogs(KConfigSkeleton *config, QWidget *parent) 0207 { 0208 QMap<QString, DictionaryPreferenceDialog *> result; 0209 const QStringList dictTypes = listDictFileTypes(); 0210 for (const QString &dictType : dictTypes) { 0211 DictFile *tempDictFile = makeDictFile(dictType); 0212 DictionaryPreferenceDialog *newDialog = tempDictFile->preferencesWidget(config, parent); 0213 0214 if (newDialog == nullptr) { 0215 delete tempDictFile; 0216 continue; 0217 } 0218 0219 result.insert(dictType, newDialog); 0220 delete tempDictFile; 0221 } 0222 0223 return result; 0224 } 0225 0226 /** 0227 * Return a list of the dictionaries by their name (our key) 0228 * Note that this dictionary name does not necessarily have to have anything 0229 * to do with the actual dictionary name... 0230 */ 0231 QStringList DictionaryManager::listDictionaries() const 0232 { 0233 QStringList ret; 0234 for (DictFile *it : d->dictManagers) { 0235 ret.append(it->getName()); 0236 } 0237 0238 return ret; 0239 } 0240 0241 /** 0242 * IMPORTANT: To add a dictionary type, you have to manually add the creation 0243 * step here, the prev method, and \#include your header file above. If you have 0244 * fully implemented the interface in DictionaryManager.h, It should simply work. 0245 */ 0246 QStringList DictionaryManager::listDictFileTypes() 0247 { 0248 QStringList list; 0249 list.append(EDICT); 0250 list.append(KANJIDIC); 0251 0252 // Add your dictionary type here! 0253 0254 return list; 0255 } 0256 0257 /** 0258 * Return the dictionary type and file used by a named dictionary. 0259 * returns a pair of empty QStrings if you specify an invalid name 0260 * 0261 * @param name the name of the dictionary, as given in the addDictionary method 0262 */ 0263 QPair<QString, QString> DictionaryManager::listDictionaryInfo(const QString &name) const 0264 { 0265 if (!d->dictManagers.contains(name)) // This name not in list! 0266 { 0267 return qMakePair(QString(), QString()); 0268 } 0269 0270 return qMakePair(d->dictManagers[name]->getName(), d->dictManagers[name]->getFile()); 0271 } 0272 0273 /** 0274 * Return a list of the names of each dictionary of a given type. 0275 * 0276 * @param type the type of the dictionary we want a list of 0277 */ 0278 QStringList DictionaryManager::listDictionariesOfType(const QString &type) const 0279 { 0280 QStringList ret; 0281 QHash<QString, DictFile *>::const_iterator it = d->dictManagers.constBegin(); 0282 while (it != d->dictManagers.constEnd()) { 0283 if (it.value()->getType() == type) { 0284 ret.append(it.key()); 0285 } 0286 0287 ++it; 0288 } 0289 0290 return ret; 0291 } 0292 0293 /** 0294 * Load preference settings for a particular dictionary 0295 */ 0296 void DictionaryManager::loadDictSettings(const QString &dictName, KConfigSkeleton *config) 0297 { 0298 DictFile *dict = this->makeDictFile(dictName); 0299 if (dict != nullptr) { 0300 config->setCurrentGroup("dicts_"_L1 + dictName.toLower()); 0301 dict->loadSettings(config); 0302 delete dict; 0303 } 0304 } 0305 0306 void DictionaryManager::loadSettings(const KConfig &config) 0307 { 0308 Q_UNUSED(config) 0309 // TODO 0310 } 0311 0312 /** 0313 * IMPORTANT: To add a dictionary type, you have to manually add the creation 0314 * step here, the next method, and \#include your header file above. If you have 0315 * fully implemented the interface in dictionarymanager.h, It should simply work. 0316 */ 0317 DictFile *DictionaryManager::makeDictFile(const QString &type) 0318 { 0319 if (type == EDICT) { 0320 return new DictFileEdict(); 0321 } else if (type == KANJIDIC) { 0322 return new DictFileKanjidic(); 0323 } 0324 0325 // Add new dictionary types here!!! 0326 0327 return nullptr; 0328 } 0329 0330 void DictionaryManager::removeAllDictionaries() 0331 { 0332 qDeleteAll(d->dictManagers); 0333 d->dictManagers.clear(); 0334 } 0335 0336 /** 0337 * Remove a dictionary from the list, and delete the dictionary object 0338 * (it should close files, deallocate memory, etc). 0339 * 0340 * @param name the name of the dictionary, as given in the addDictionary method 0341 */ 0342 bool DictionaryManager::removeDictionary(const QString &name) 0343 { 0344 DictFile *file = d->dictManagers.take(name); 0345 delete file; 0346 return true; 0347 }