File indexing completed on 2024-12-08 06:28:23
0001 /* 0002 This file is part of Kiten, a KDE Japanese Reference Tool 0003 SPDX-FileCopyrightText: 2001 Jason Katz-Brown <jason@katzbrown.com> 0004 SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com> 0005 SPDX-FileCopyrightText: 2006 Eric Kjeldergaard <kjelderg@gmail.com> 0006 SPDX-FileCopyrightText: 2011 Daniel E. Moctezuma <democtezuma@gmail.com> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "entrylist.h" 0012 0013 #include <KLocalizedString> 0014 0015 #include "DictEdict/dictfileedict.h" 0016 #include "DictEdict/entryedict.h" 0017 #include "kitenmacros.h" 0018 0019 using namespace Qt::StringLiterals; 0020 0021 class EntryList::Private 0022 { 0023 public: 0024 Private() 0025 : storedScrollValue(0) 0026 , sorted(false) 0027 , sortedByDictionary(false) 0028 { 0029 } 0030 0031 Private(const Private &other) = default; 0032 Private &operator=(const Private &other) = default; 0033 0034 int storedScrollValue; 0035 bool sorted; 0036 bool sortedByDictionary; 0037 DictQuery query; 0038 }; 0039 0040 /* sorts the EntryList in a C++ish, thread-safe manner. */ 0041 class SortFunctor 0042 { 0043 public: 0044 QStringList *dictionary_order; 0045 QStringList *sort_order; 0046 0047 bool operator()(const Entry *n1, const Entry *n2) const 0048 { 0049 return n1->sort(*n2, *dictionary_order, *sort_order); 0050 } 0051 }; 0052 0053 EntryList::EntryList() 0054 : QList<Entry *>() 0055 , d(new Private) 0056 { 0057 } 0058 0059 EntryList::EntryList(const EntryList &old) 0060 : QList<Entry *>(old) 0061 , d(new Private(*(old.d))) 0062 { 0063 } 0064 0065 EntryList::~EntryList() 0066 { 0067 delete d; 0068 // kdDebug() << "A copy of EntryList is being deleted... watch your memory!" << endl; 0069 } 0070 0071 int EntryList::scrollValue() const 0072 { 0073 return d->storedScrollValue; 0074 } 0075 0076 void EntryList::setScrollValue(int val) 0077 { 0078 d->storedScrollValue = val; 0079 } 0080 0081 void EntryList::deleteAll() 0082 { 0083 while (!this->isEmpty()) { 0084 delete this->takeFirst(); 0085 } 0086 0087 d->sorted = false; 0088 } 0089 0090 /* Returns the EntryList as HTML */ 0091 // TODO: Some intelligent decision making regarding when to print what when AutoPrinting is on 0092 QString EntryList::toHTML(unsigned int start, unsigned int length) const 0093 { 0094 unsigned int max = count(); 0095 if (start > max) { 0096 return {}; 0097 } 0098 if (start + length > max) { 0099 length = max - start; 0100 } 0101 0102 QString result; 0103 QString temp; 0104 QString &lastDictionary = temp; 0105 const QString fromDictionary = i18n("From Dictionary:"); 0106 QString query(getQuery()); 0107 0108 bool firstTimeDeinflection = true; 0109 bool firstTimeCommon = true; 0110 bool firstTimeUncommon = true; 0111 for (unsigned int i = 0; i < max; ++i) { 0112 Entry *entry = at(i); 0113 if (d->sortedByDictionary) { 0114 const QString &newDictionary = entry->getDictName(); 0115 if (firstTimeDeinflection && newDictionary == EDICT && DictFileEdict::deinflectionLabel) { 0116 const QString &label = *DictFileEdict::deinflectionLabel; 0117 const QString &type = *DictFileEdict::wordType; 0118 const QString &message = i18nc( 0119 "%1 is a word type (verb or adjective)." 0120 " %2 is a verb or adjective tense." 0121 " Example: 'Entered verb in past tense'.", 0122 "Entered %1 in %2 form", 0123 type, 0124 label); 0125 0126 result += QStringLiteral("<div style=\"font-style:italic\">%1</div>").arg(message); 0127 0128 firstTimeDeinflection = false; 0129 } 0130 0131 if (lastDictionary != newDictionary) { 0132 lastDictionary = newDictionary; 0133 result += QStringLiteral("<div class=\"DictionaryHeader\">%1 %2</div>").arg(fromDictionary).arg(newDictionary); 0134 firstTimeCommon = true; 0135 firstTimeUncommon = true; 0136 } 0137 } 0138 0139 if (getQuery().getFilterType() == DictQuery::CommonUncommon) { 0140 if (entry->getDictionaryType() == EDICT) { 0141 auto entryEdict = static_cast<EntryEdict *>(entry); 0142 if (entryEdict->isCommon() && firstTimeCommon) { 0143 result += QStringLiteral("<div class=\"CommonHeader\">%1</div>").arg(i18n("Common")); 0144 firstTimeCommon = false; 0145 } else if (!entryEdict->isCommon() && firstTimeUncommon) { 0146 result += QStringLiteral("<div class=\"UncommonHeader\">%1</div>").arg(i18n("Uncommon")); 0147 firstTimeUncommon = false; 0148 } 0149 } 0150 } 0151 0152 if (length-- > 0) { 0153 result += QStringLiteral("<div class=\"%1\" index=\"%2\" dict=\"%3\">%4</div>") 0154 .arg(i % 2 == 0 ? "Entry"_L1 : "Entry odd"_L1) 0155 .arg(QString::number(i)) 0156 .arg(entry->getDictName()) 0157 .arg(entry->toHTML()); 0158 } else { 0159 break; 0160 } 0161 } 0162 // result.replace( query, "<query>" + query + "</query>" ); 0163 return result; 0164 } 0165 0166 QString EntryList::toKVTML(unsigned int start, unsigned int length) const 0167 { 0168 unsigned int max = count(); 0169 if (start > max) { 0170 return {}; 0171 } 0172 if (start + length > max) { 0173 length = max - start; 0174 } 0175 0176 QString result = QStringLiteral( 0177 "<?xml version=\"1.0\"?>\n<!DOCTYPE kvtml SYSTEM \"kvoctrain.dtd\">\n" 0178 "<kvtml encoding=\"UTF-8\" " 0179 " generator=\"kiten v42.0\"" 0180 " title=\"To be determined\">\n"); 0181 for (Entry *it : *this) { 0182 if (length-- > 0) { 0183 result = result + it->toKVTML() + '\n'_L1; 0184 } else { 0185 break; 0186 } 0187 } 0188 return result + QStringLiteral("</kvtml>\n"); 0189 } 0190 0191 QString EntryList::toHTML() const 0192 { 0193 return toHTML(0, count()); 0194 } 0195 0196 /* Returns the EntryList as HTML */ 0197 // TODO: Some intelligent decision making... regarding the output format (differ for 0198 // different types of searches? 0199 QString EntryList::toString(unsigned int start, unsigned int length) const 0200 { 0201 unsigned int max = count(); 0202 if (start > max) { 0203 return {}; 0204 } 0205 if (start + length > max) { 0206 length = max - start; 0207 } 0208 0209 QString result; 0210 for (Entry *it : *this) { 0211 if (length-- > 0) { 0212 result = result + it->toString(); 0213 } else { 0214 break; 0215 } 0216 } 0217 0218 return result; 0219 } 0220 0221 QString EntryList::toString() const 0222 { 0223 return toString(0, count()); 0224 } 0225 0226 void EntryList::sort(QStringList &sortOrder, QStringList &dictionaryOrder) 0227 { 0228 // Don't shortcut sorting, unless we start to keep track of the last sorting order, 0229 // Otherwise we won't respond when the user changes the sorting order 0230 SortFunctor sorter; 0231 sorter.dictionary_order = &dictionaryOrder; 0232 sorter.sort_order = &sortOrder; 0233 0234 std::stable_sort(this->begin(), this->end(), sorter); 0235 d->sorted = true; 0236 d->sortedByDictionary = !dictionaryOrder.empty(); 0237 } 0238 0239 const EntryList &EntryList::operator+=(const EntryList &other) 0240 { 0241 for (Entry *it : other) { 0242 this->append(it); 0243 } 0244 if (!other.empty()) { 0245 d->sorted = false; 0246 } 0247 0248 return *this; 0249 } 0250 0251 const EntryList &EntryList::operator=(const EntryList &other) 0252 { 0253 QList<Entry *>::operator=(other); 0254 *d = *(other.d); 0255 0256 return *this; 0257 } 0258 0259 void EntryList::appendList(const EntryList *other) 0260 { 0261 for (Entry *it : *other) { 0262 append(it); 0263 } 0264 0265 if (!other->empty()) { 0266 d->sorted = false; 0267 } 0268 } 0269 0270 /** 0271 * This method retrieves an earlier saved query in the EntryList, 0272 * this should be the query that generated the list. 0273 */ 0274 DictQuery EntryList::getQuery() const 0275 { 0276 return d->query; 0277 } 0278 0279 /** 0280 * This allows us to save a query in the EntryList for later retrieval 0281 */ 0282 void EntryList::setQuery(const DictQuery &newQuery) 0283 { 0284 d->query = newQuery; 0285 }