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 }