File indexing completed on 2024-04-21 07:34:45

0001 /*
0002  * read a KEduVocDocument from a KVTML file
0003  * SPDX-FileCopyrightText: 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
0004  * SPDX-FileCopyrightText: 2005 Eric Pignet <eric at erixpage.com>
0005  * SPDX-FileCopyrightText: 2007 Peter Hedlund <peter.hedlund@kdemail.net>
0006  * SPDX-FileCopyrightText: 2007-2010 Frederik Gladhorn <gladhorn@kde.org>
0007  * SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 
0010 #include "keduvockvtml2reader.h"
0011 
0012 #include <KLocalizedString>
0013 #include <QDir>
0014 #include <QIODevice>
0015 #include <QList>
0016 #include <QTextStream>
0017 
0018 #include "keduvoccommon_p.h"
0019 #include "keduvockvtmlreader.h"
0020 #include "keduvocleitnerbox.h"
0021 #include "keduvoclesson.h"
0022 #include "keduvocwordtype.h"
0023 #include "kvtml2defs.h"
0024 
0025 #include <QDebug>
0026 
0027 KEduVocKvtml2Reader::KEduVocKvtml2Reader(QIODevice &file)
0028     : m_inputFile(&file)
0029 {
0030 }
0031 
0032 bool KEduVocKvtml2Reader::isParsable()
0033 {
0034     QTextStream ts(m_inputFile);
0035     QString line1(ts.readLine());
0036     QString line2(ts.readLine());
0037 
0038     m_inputFile->seek(0);
0039     return ((line1.startsWith(QLatin1String("<?xml"))) && (line2.indexOf(KVTML_TAG, 0) > 0));
0040 }
0041 
0042 KEduVocDocument::FileType KEduVocKvtml2Reader::fileTypeHandled()
0043 {
0044     return KEduVocDocument::Kvtml;
0045 }
0046 
0047 KEduVocDocument::ErrorCode KEduVocKvtml2Reader::read(KEduVocDocument &doc)
0048 {
0049     m_doc = &doc;
0050 
0051     QDomDocument domDoc(QStringLiteral("KEduVocDocument"));
0052 
0053     if (!domDoc.setContent(m_inputFile, &m_errorMessage))
0054         return KEduVocDocument::InvalidXml;
0055 
0056     QDomElement domElementKvtml = domDoc.documentElement();
0057     if (domElementKvtml.tagName() != KVTML_TAG) {
0058         m_errorMessage = i18n("This is not a KDE Vocabulary document.");
0059         return KEduVocDocument::FileTypeUnknown;
0060     }
0061 
0062     if (domElementKvtml.attribute(KVTML_VERSION).toFloat() < 2.0) {
0063         // read the file with the old format
0064 
0065         // first reset the file to the beginning
0066         m_inputFile->seek(0);
0067         KEduVocKvtmlReader oldFormat(*m_inputFile);
0068 
0069         // get the return value
0070         KEduVocDocument::ErrorCode retval = oldFormat.read(doc);
0071 
0072         // pass the errormessage up
0073         m_errorMessage = oldFormat.errorMessage();
0074         return retval;
0075     }
0076 
0077     //-------------------------------------------------------------------------
0078     // Information
0079     //-------------------------------------------------------------------------
0080 
0081     QDomElement info = domElementKvtml.firstChildElement(KVTML_INFORMATION);
0082     if (!info.isNull()) {
0083         if (!readInformation(info))
0084             return KEduVocDocument::FileReaderFailed;
0085     }
0086 
0087     bool result = readGroups(domElementKvtml); // read sub-groups
0088 
0089     return result ? KEduVocDocument::NoError : KEduVocDocument::FileReaderFailed;
0090 }
0091 
0092 bool KEduVocKvtml2Reader::readInformation(QDomElement &informationElement)
0093 {
0094     // read the generator
0095     QDomElement currentElement = informationElement.firstChildElement(KVTML_GENERATOR);
0096     if (!currentElement.isNull()) {
0097         m_doc->setGenerator(currentElement.text());
0098         // add the version if it's there
0099         int pos = m_doc->generator().lastIndexOf(KVD_VERS_PREFIX);
0100         if (pos >= 0) {
0101             m_doc->setVersion(m_doc->generator().remove(0, pos + 2));
0102         }
0103     }
0104 
0105     // read the title
0106     currentElement = informationElement.firstChildElement(KVTML_TITLE);
0107     if (!currentElement.isNull()) {
0108         m_doc->setTitle(currentElement.text());
0109     }
0110 
0111     // read the author
0112     currentElement = informationElement.firstChildElement(KVTML_AUTHOR);
0113     if (!currentElement.isNull()) {
0114         m_doc->setAuthor(currentElement.text());
0115     }
0116 
0117     currentElement = informationElement.firstChildElement(KVTML_AUTHORCONTACT);
0118     if (!currentElement.isNull()) {
0119         m_doc->setAuthorContact(currentElement.text());
0120     }
0121 
0122     // read the license
0123     currentElement = informationElement.firstChildElement(KVTML_LICENSE);
0124     if (!currentElement.isNull()) {
0125         m_doc->setLicense(currentElement.text());
0126     }
0127 
0128     // read the comment
0129     currentElement = informationElement.firstChildElement(KVTML_COMMENT);
0130     if (!currentElement.isNull()) {
0131         m_doc->setDocumentComment(currentElement.text());
0132     }
0133 
0134     // read the category
0135     currentElement = informationElement.firstChildElement(KVTML_CATEGORY);
0136     if (!currentElement.isNull()) {
0137         m_doc->setCategory(currentElement.text());
0138     }
0139 
0140     return true;
0141 }
0142 
0143 bool KEduVocKvtml2Reader::readGroups(QDomElement &domElementParent)
0144 {
0145     bool result = false;
0146 
0147     QDomElement groupElement = domElementParent.firstChildElement(KVTML_IDENTIFIERS);
0148 
0149     QDomElement currentElement;
0150 
0151     // ensure backwards compatibility - in kde 4.1 and earlier tenses were direct properties of the document class.
0152     // now they are moved into the individual identifiers
0153     QStringList tensesCompability;
0154     groupElement = groupElement.firstChildElement(KVTML_TENSES);
0155     if (!groupElement.isNull()) {
0156         tensesCompability = readTenses(groupElement);
0157     }
0158 
0159     groupElement = domElementParent.firstChildElement(KVTML_IDENTIFIERS);
0160     if (!groupElement.isNull()) {
0161         QDomNodeList entryList = groupElement.elementsByTagName(KVTML_IDENTIFIER);
0162         if (entryList.length() <= 0) {
0163             m_errorMessage = i18n("missing identifier elements from identifiers tag");
0164             return false;
0165         }
0166 
0167         for (int i = 0; i < entryList.count(); ++i) {
0168             currentElement = entryList.item(i).toElement();
0169             if (currentElement.parentNode() == groupElement) {
0170                 result = readIdentifier(currentElement);
0171                 if (!result) {
0172                     return false;
0173                 }
0174                 if (!tensesCompability.isEmpty()) {
0175                     m_doc->identifier(i).setTenseList(tensesCompability);
0176                 }
0177             }
0178         }
0179     }
0180 
0181     groupElement = domElementParent.firstChildElement(KVTML_ENTRIES);
0182     if (!groupElement.isNull()) {
0183         QDomNodeList entryList = groupElement.elementsByTagName(KVTML_ENTRY);
0184         for (int i = 0; i < entryList.count(); ++i) {
0185             currentElement = entryList.item(i).toElement();
0186             if (currentElement.parentNode() == groupElement) {
0187                 result = readEntry(currentElement);
0188                 if (!result)
0189                     return false;
0190             }
0191         }
0192     }
0193 
0194     readSynonymsAntonymsFalseFriends(domElementParent);
0195 
0196     groupElement = domElementParent.firstChildElement(KVTML_WORDTYPES);
0197     if (!groupElement.isNull()) {
0198         readChildWordTypes(m_doc->wordTypeContainer(), groupElement);
0199     }
0200 
0201     groupElement = domElementParent.firstChildElement(KVTML_LEITNERBOXES);
0202     if (!groupElement.isNull()) {
0203         readLeitner(m_doc->leitnerContainer(), groupElement);
0204     }
0205 
0206     groupElement = domElementParent.firstChildElement(KVTML_LESSONS);
0207     if (!groupElement.isNull()) {
0208         readChildLessons(m_doc->lesson(), groupElement);
0209     }
0210 
0211     // Additional cleanup: Put orphaned entries without a lesson into a default lesson.
0212     KEduVocLesson *defaultLesson = new KEduVocLesson(i18n("Default Lesson"), m_doc->lesson());
0213 
0214     // now make sure we don't have any orphan entries
0215     foreach (KEduVocExpression *entry, m_allEntries) {
0216         if (!entry->lesson()) {
0217             defaultLesson->appendEntry(entry);
0218         }
0219     }
0220 
0221     if (defaultLesson->entryCount() > 0) {
0222         m_doc->lesson()->appendChildContainer(defaultLesson);
0223     } else {
0224         delete defaultLesson;
0225     }
0226 
0227     return true;
0228 }
0229 
0230 bool KEduVocKvtml2Reader::readIdentifier(QDomElement &identifierElement)
0231 {
0232     bool result = true;
0233     int id = identifierElement.attribute(KVTML_ID).toInt(&result);
0234     if (!result) {
0235         m_errorMessage = i18n("identifier missing id");
0236         return false;
0237     }
0238 
0239     // generate empty identifiers in the doc
0240     for (int i = m_doc->identifierCount(); i <= id; i++) {
0241         m_doc->appendIdentifier(KEduVocIdentifier());
0242     }
0243 
0244     // the first element, create the identifier, even if empty
0245     QDomElement currentElement = identifierElement.firstChildElement(KVTML_NAME);
0246     m_doc->identifier(id).setName(currentElement.text());
0247 
0248     currentElement = identifierElement.firstChildElement(KVTML_LOCALE);
0249     m_doc->identifier(id).setLocale(currentElement.text());
0250 
0251     currentElement = identifierElement.firstChildElement(KVTML_IDENTIFIERTYPE);
0252     if (!currentElement.isNull()) {
0253         // TODO: do something with the type
0254     }
0255 
0256     // read sub-parts
0257     currentElement = identifierElement.firstChildElement(KVTML_ARTICLE);
0258     if (!currentElement.isNull()) {
0259         readArticle(currentElement, id);
0260     }
0261 
0262     currentElement = identifierElement.firstChildElement(KVTML_PERSONALPRONOUNS);
0263     if (!currentElement.isNull()) {
0264         KEduVocPersonalPronoun personalPronoun;
0265         readPersonalPronoun(currentElement, personalPronoun);
0266         m_doc->identifier(id).setPersonalPronouns(personalPronoun);
0267     }
0268 
0269     QStringList tenses = readTenses(identifierElement);
0270 
0271     m_doc->identifier(id).setTenseList(tenses);
0272 
0273     return result;
0274 }
0275 
0276 bool KEduVocKvtml2Reader::readEntry(QDomElement &entryElement)
0277 {
0278     QDomElement currentElement;
0279     bool result = true;
0280 
0281     // get entry id
0282     int id = entryElement.attribute(KVTML_ID).toInt(&result);
0283     if (!result) {
0284         m_errorMessage = i18n("entry missing id");
0285         return false;
0286     }
0287 
0288     KEduVocExpression *expr = new KEduVocExpression;
0289 
0290     // read info tags: inactive, inquery, and sizehint
0291     currentElement = entryElement.firstChildElement(KVTML_DEACTIVATED);
0292     if (!currentElement.isNull()) {
0293         // set the active state of the expression
0294         if (currentElement.text() == KVTML_TRUE) {
0295             expr->setActive(false);
0296         } else {
0297             expr->setActive(true);
0298         }
0299     }
0300 
0301     // read translation children
0302     QDomNodeList translationList = entryElement.elementsByTagName(KVTML_TRANSLATION);
0303 
0304     for (int i = 0; i < translationList.count(); ++i) {
0305         currentElement = translationList.item(i).toElement();
0306         if (currentElement.parentNode() == entryElement) {
0307             result = readTranslation(currentElement, expr, i);
0308             if (!result)
0309                 return false;
0310         }
0311     }
0312 
0313     if (expr->translationIndices().size() == 0) {
0314         qDebug() << "Found entry with no words in it." << id;
0315         expr->setTranslation(0, QString());
0316     }
0317 
0318     Q_ASSERT(expr);
0319 
0320     // TODO: probably should insert at id position with a check to see if it exists
0321     // may be useful for detecting corrupt documents
0322     m_allEntries[id] = expr;
0323     return result;
0324 }
0325 
0326 bool KEduVocKvtml2Reader::readTranslation(QDomElement &translationElement, KEduVocExpression *expr, int index)
0327 {
0328     // read the text, grade, declension and conjugation
0329     expr->translation(index)->fromKVTML2(translationElement);
0330     QDomElement currentElement;
0331 
0332     // article grade
0333     currentElement = translationElement.firstChildElement(KVTML_ARTICLE);
0334     if (!currentElement.isNull()) {
0335         KEduVocText article;
0336         article.fromKVTML2(currentElement);
0337         expr->translation(index)->setArticle(article);
0338     }
0339 
0340     // comparisons
0341     currentElement = translationElement.firstChildElement(KVTML_COMPARISON);
0342     if (!currentElement.isNull()) {
0343         readComparison(currentElement, expr->translation(index));
0344     }
0345 
0346     // multiple choice
0347     currentElement = translationElement.firstChildElement(KVTML_MULTIPLECHOICE);
0348     if (!currentElement.isNull()) {
0349         readMultipleChoice(currentElement, expr->translation(index));
0350     }
0351 
0352     // image
0353     currentElement = translationElement.firstChildElement(KVTML_IMAGE);
0354     if (!currentElement.isNull()) {
0355         QUrl imageUrl(currentElement.text());
0356         if (imageUrl.isLocalFile() && QDir::isRelativePath(imageUrl.toLocalFile())) {
0357             imageUrl = QUrl(m_doc->url().toString(QUrl::RemoveFilename) + imageUrl.toLocalFile());
0358         }
0359         expr->translation(index)->setImageUrl(imageUrl);
0360     }
0361 
0362     // sound
0363     currentElement = translationElement.firstChildElement(KVTML_SOUND);
0364     if (!currentElement.isNull()) {
0365         QUrl soundUrl(currentElement.text());
0366         if (soundUrl.isLocalFile() && QDir::isRelativePath(soundUrl.toLocalFile())) {
0367             soundUrl = QUrl(m_doc->url().toString(QUrl::RemoveFilename) + soundUrl.toLocalFile());
0368         }
0369         expr->translation(index)->setSoundUrl(soundUrl);
0370     }
0371 
0372     return true;
0373 }
0374 
0375 bool KEduVocKvtml2Reader::readChildLessons(KEduVocLesson *parentLesson, QDomElement &lessonElement)
0376 {
0377     QDomElement currentElement = lessonElement.firstChildElement(KVTML_CONTAINER);
0378     while (!currentElement.isNull()) {
0379         readLesson(parentLesson, currentElement);
0380         currentElement = currentElement.nextSiblingElement(KVTML_CONTAINER);
0381     }
0382     return true;
0383 }
0384 
0385 bool KEduVocKvtml2Reader::readLesson(KEduVocLesson *parentLesson, QDomElement &lessonElement)
0386 {
0387     //<name>Lesson name</name>
0388     QDomElement currentElement = lessonElement.firstChildElement(KVTML_NAME);
0389     KEduVocLesson *lesson = new KEduVocLesson(currentElement.text(), parentLesson);
0390     parentLesson->appendChildContainer(lesson);
0391 
0392     readChildLessons(lesson, lessonElement);
0393 
0394     //<query>true</query>
0395     currentElement = lessonElement.firstChildElement(KVTML_INPRACTICE);
0396     lesson->setInPractice(currentElement.text() == KVTML_TRUE);
0397 
0398     //<entry id="123"/>
0399     currentElement = lessonElement.firstChildElement(KVTML_ENTRY);
0400     while (!currentElement.isNull()) {
0401         bool result = false;
0402         int entryId = currentElement.attribute(KVTML_ID).toInt(&result);
0403         if (result) {
0404             if (m_allEntries[entryId]) {
0405                 lesson->appendEntry(m_allEntries[entryId]);
0406             }
0407         }
0408         currentElement = currentElement.nextSiblingElement(KVTML_ENTRY);
0409     }
0410     return true;
0411 }
0412 
0413 bool KEduVocKvtml2Reader::readSynonymsAntonymsFalseFriends(QDomElement &rootElement)
0414 {
0415     QDomElement pairElement;
0416     for (int type = KEduVocTranslation::Synonym; type <= KEduVocTranslation::FalseFriend; type++) {
0417         switch (type) {
0418         case KEduVocTranslation::Synonym:
0419             pairElement = rootElement.firstChildElement(KVTML_SYNONYM);
0420             break;
0421         case KEduVocTranslation::Antonym:
0422             pairElement = rootElement.firstChildElement(KVTML_ANTONYM);
0423             break;
0424         case KEduVocTranslation::FalseFriend:
0425             pairElement = rootElement.firstChildElement(KVTML_FALSEFRIEND);
0426             break;
0427         }
0428         // pair
0429         pairElement = pairElement.firstChildElement(KVTML_PAIR);
0430         while (!pairElement.isNull()) {
0431             //<entry id="123"/>
0432             QDomElement entryElement = pairElement.firstChildElement(KVTML_ENTRY);
0433             int firstEntryId = entryElement.attribute(KVTML_ID).toInt();
0434 
0435             QDomElement translationElement = entryElement.firstChildElement(KVTML_TRANSLATION);
0436             int firstTranslationId = translationElement.attribute(KVTML_ID).toInt();
0437 
0438             // second entry
0439             entryElement = entryElement.nextSiblingElement(KVTML_ENTRY);
0440             int secondEntryId = entryElement.attribute(KVTML_ID).toInt();
0441             translationElement = entryElement.firstChildElement(KVTML_TRANSLATION);
0442             int secondTranslationId = translationElement.attribute(KVTML_ID).toInt();
0443 
0444             // pair them up
0445             KEduVocTranslation *first = m_allEntries[firstEntryId]->translation(firstTranslationId);
0446             KEduVocTranslation *second = m_allEntries[secondEntryId]->translation(secondTranslationId);
0447 
0448             switch (type) {
0449             case KEduVocTranslation::Synonym:
0450                 first->addSynonym(second);
0451                 second->addSynonym(first);
0452                 break;
0453             case KEduVocTranslation::Antonym:
0454                 first->addAntonym(second);
0455                 second->addAntonym(first);
0456                 break;
0457             case KEduVocTranslation::FalseFriend:
0458                 first->addFalseFriend(second);
0459                 second->addFalseFriend(first);
0460                 break;
0461             }
0462             pairElement = pairElement.nextSiblingElement(KVTML_PAIR);
0463         }
0464     }
0465     return true;
0466 }
0467 
0468 bool KEduVocKvtml2Reader::readArticle(QDomElement &articleElement, int identifierNum)
0469 /*
0470  <article>
0471   <singlular>
0472     <definite>
0473         <male>der</male>
0474         <female>die</female>
0475         <neutral>das</neutral>
0476     </definite>
0477     <indefinite>
0478         <male>ein</male>
0479         <female>eine</female>
0480         <neutral>ein</neutral>
0481     </indefinite>
0482   </singular>
0483   <dual>
0484   </dual>
0485  </article>
0486 */
0487 {
0488     QMap<int, KEduVocWordFlag::Flags> numbers;
0489     numbers[0] = KEduVocWordFlag::Singular;
0490     numbers[1] = KEduVocWordFlag::Dual;
0491     numbers[2] = KEduVocWordFlag::Plural;
0492     QMap<int, KEduVocWordFlag::Flags> genders;
0493     genders[0] = KEduVocWordFlag::Masculine;
0494     genders[1] = KEduVocWordFlag::Feminine;
0495     genders[2] = KEduVocWordFlag::Neuter;
0496     QMap<int, KEduVocWordFlag::Flags> defs;
0497     defs[0] = KEduVocWordFlag::Definite;
0498     defs[1] = KEduVocWordFlag::Indefinite;
0499 
0500     for (int num = 0; num <= 2; ++num) {
0501         QDomElement numberElement = articleElement.firstChildElement(KVTML_GRAMMATICAL_NUMBER[num]);
0502         if (!numberElement.isNull()) {
0503             // definite
0504             for (int def = 0; def <= 1; ++def) {
0505                 QDomElement defElement = numberElement.firstChildElement(KVTML_GRAMMATICAL_DEFINITENESS[def]);
0506                 if (!defElement.isNull()) {
0507                     // male
0508                     for (int gen = 0; gen <= 2; ++gen) {
0509                         QDomElement genderElement = defElement.firstChildElement(KVTML_GRAMMATICAL_GENDER[gen]);
0510                         if (!genderElement.isNull()) {
0511                             m_doc->identifier(identifierNum).article().setArticle(genderElement.text(), numbers[num] | defs[def] | genders[gen]);
0512                         }
0513                     }
0514                 }
0515             }
0516         }
0517     }
0518 
0519     return true;
0520 }
0521 
0522 bool KEduVocKvtml2Reader::readChildWordTypes(KEduVocWordType *parentContainer, QDomElement &lessonElement)
0523 {
0524     QDomElement currentElement = lessonElement.firstChildElement(KVTML_CONTAINER);
0525     while (!currentElement.isNull()) {
0526         readWordType(parentContainer, currentElement);
0527         currentElement = currentElement.nextSiblingElement(KVTML_CONTAINER);
0528     }
0529     return true;
0530 }
0531 
0532 bool KEduVocKvtml2Reader::readLeitner(KEduVocLeitnerBox *parentContainer, QDomElement &leitnerParentElement)
0533 {
0534     QDomElement leitnerElement = leitnerParentElement.firstChildElement(KVTML_CONTAINER);
0535     while (!leitnerElement.isNull()) {
0536         QString name = leitnerElement.firstChildElement(KVTML_NAME).text();
0537 
0538         KEduVocLeitnerBox *leitner = new KEduVocLeitnerBox(name, parentContainer);
0539         parentContainer->appendChildContainer(leitner);
0540         // for leitner we only allow a flat list, no sub boxes.
0541 
0542         // read entries
0543         QDomElement entryElement = leitnerElement.firstChildElement(KVTML_ENTRY);
0544         while (!entryElement.isNull()) {
0545             // read <entry id="123"></entryid>
0546             int entryId = entryElement.attribute(KVTML_ID).toInt();
0547             QDomElement translationElement = entryElement.firstChildElement(KVTML_TRANSLATION);
0548             while (!translationElement.isNull()) {
0549                 // <translation id="234"/>
0550                 int translationId = translationElement.attribute(KVTML_ID).toInt();
0551                 m_allEntries.value(entryId)->translation(translationId)->setLeitnerBox(leitner);
0552                 translationElement = translationElement.nextSiblingElement(KVTML_TRANSLATION);
0553             }
0554             entryElement = entryElement.nextSiblingElement(KVTML_ENTRY);
0555         }
0556         leitnerElement = leitnerElement.nextSiblingElement(KVTML_CONTAINER);
0557     }
0558     return true;
0559 }
0560 
0561 bool KEduVocKvtml2Reader::readWordType(KEduVocWordType *parentContainer, QDomElement &typeElement)
0562 {
0563     // set type and specialtype
0564     QString typeName = typeElement.firstChildElement(KVTML_NAME).text();
0565 
0566     KEduVocWordType *wordTypeContainer = new KEduVocWordType(typeName, parentContainer);
0567     parentContainer->appendChildContainer(wordTypeContainer);
0568 
0569     QString specialType = typeElement.firstChildElement(KVTML_SPECIALWORDTYPE).text();
0570     if (!specialType.isEmpty()) {
0571         // get the localized version
0572         if (specialType == KVTML_SPECIALWORDTYPE_NOUN) {
0573             wordTypeContainer->setWordType(KEduVocWordFlag::Noun);
0574         }
0575         if (specialType == KVTML_SPECIALWORDTYPE_VERB) {
0576             wordTypeContainer->setWordType(KEduVocWordFlag::Verb);
0577         }
0578         if (specialType == KVTML_SPECIALWORDTYPE_ADVERB) {
0579             wordTypeContainer->setWordType(KEduVocWordFlag::Adverb);
0580         }
0581         if (specialType == KVTML_SPECIALWORDTYPE_ADJECTIVE) {
0582             wordTypeContainer->setWordType(KEduVocWordFlag::Adjective);
0583         }
0584         if (specialType == KVTML_SPECIALWORDTYPE_NOUN_MALE) {
0585             wordTypeContainer->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Masculine);
0586         }
0587         if (specialType == KVTML_SPECIALWORDTYPE_NOUN_FEMALE) {
0588             wordTypeContainer->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Feminine);
0589         }
0590         if (specialType == KVTML_SPECIALWORDTYPE_NOUN_NEUTRAL) {
0591             wordTypeContainer->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Neuter);
0592         }
0593         if (specialType == KVTML_SPECIALWORDTYPE_CONJUNCTION) {
0594             wordTypeContainer->setWordType(KEduVocWordFlag::Conjunction);
0595         }
0596     } // special type
0597 
0598     // read entries
0599     QDomElement entryElement = typeElement.firstChildElement(KVTML_ENTRY);
0600     while (!entryElement.isNull()) {
0601         // read <entry id="123"></entryid>
0602         int entryId = entryElement.attribute(KVTML_ID).toInt();
0603         QDomElement translationElement = entryElement.firstChildElement(KVTML_TRANSLATION);
0604         while (!translationElement.isNull()) {
0605             // <translation id="234"/>
0606             int translationId = translationElement.attribute(KVTML_ID).toInt();
0607             m_allEntries.value(entryId)->translation(translationId)->setWordType(wordTypeContainer);
0608             translationElement = translationElement.nextSiblingElement(KVTML_TRANSLATION);
0609         }
0610         entryElement = entryElement.nextSiblingElement(KVTML_ENTRY);
0611     }
0612 
0613     readChildWordTypes(wordTypeContainer, typeElement);
0614 
0615     return true;
0616 }
0617 
0618 QStringList KEduVocKvtml2Reader::readTenses(QDomElement &tensesElement)
0619 {
0620     QStringList tenses;
0621 
0622     QDomNodeList tenseNodes = tensesElement.elementsByTagName(KVTML_TENSE);
0623     for (int i = 0; i < tenseNodes.count(); ++i) {
0624         QDomElement currentElement = tenseNodes.item(i).toElement();
0625         if (currentElement.parentNode() == tensesElement) {
0626             tenses.append(currentElement.text());
0627         }
0628     }
0629 
0630     return tenses;
0631 }
0632 
0633 bool KEduVocKvtml2Reader::readComparison(QDomElement &domElementParent, KEduVocTranslation *translation)
0634 /*
0635  <comparison>
0636    <comparative>better</comparative>
0637    <superlative>best</superlative>
0638  </comparison>
0639 */
0640 {
0641     QDomElement currentElement;
0642 
0643     currentElement = domElementParent.firstChildElement(KVTML_COMPARATIVE);
0644     if (!currentElement.isNull()) {
0645         KEduVocText comparative;
0646         comparative.fromKVTML2(currentElement);
0647 
0648         // be compatible for KDE < 4.5
0649         if (comparative.text().isEmpty()) {
0650             comparative.setText(currentElement.text());
0651         }
0652         translation->setComparativeForm(comparative);
0653     }
0654 
0655     currentElement = domElementParent.firstChildElement(KVTML_SUPERLATIVE);
0656     if (!currentElement.isNull()) {
0657         KEduVocText superlative;
0658         superlative.fromKVTML2(currentElement);
0659 
0660         // be compatible for KDE < 4.5
0661         if (superlative.text().isEmpty()) {
0662             superlative.setText(currentElement.text());
0663         }
0664         translation->setSuperlativeForm(superlative);
0665     }
0666     return true;
0667 }
0668 
0669 bool KEduVocKvtml2Reader::readMultipleChoice(QDomElement &multipleChoiceElement, KEduVocTranslation *translation)
0670 /*
0671  <multiplechoice>
0672    <choice>good</choice>
0673    <choice>better</choice>
0674    <choice>best</choice>
0675    <choice>best 2</choice>
0676    <choice>best 3</choice>
0677  </multiplechoice>
0678 */
0679 {
0680     QDomElement currentElement;
0681     QDomNodeList choiceNodes = multipleChoiceElement.elementsByTagName(KVTML_CHOICE);
0682     for (int i = 0; i < choiceNodes.count(); ++i) {
0683         currentElement = choiceNodes.item(i).toElement();
0684         if (currentElement.parentNode() == multipleChoiceElement) {
0685             QStringList choices = translation->getMultipleChoice();
0686             choices.append(currentElement.text());
0687             translation->setMultipleChoice(choices);
0688         }
0689     }
0690     return true;
0691 }
0692 
0693 bool KEduVocKvtml2Reader::readPersonalPronoun(QDomElement &pronounElement, KEduVocPersonalPronoun &pronoun)
0694 {
0695     pronoun.setMaleFemaleDifferent(!pronounElement.firstChildElement(KVTML_THIRD_PERSON_MALE_FEMALE_DIFFERENT).isNull());
0696     pronoun.setNeutralExists(!pronounElement.firstChildElement(KVTML_THIRD_PERSON_NEUTRAL_EXISTS).isNull());
0697     pronoun.setDualExists(!pronounElement.firstChildElement(KVTML_DUAL_EXISTS).isNull());
0698 
0699     QDomElement personElement = pronounElement.firstChildElement(KVTML_GRAMMATICAL_NUMBER[0]);
0700     if (!personElement.isNull()) {
0701         readPersonalPronounChild(personElement, pronoun, KEduVocWordFlag::Singular);
0702     }
0703 
0704     personElement = pronounElement.firstChildElement(KVTML_GRAMMATICAL_NUMBER[1]);
0705     if (!personElement.isNull()) {
0706         readPersonalPronounChild(personElement, pronoun, KEduVocWordFlag::Dual);
0707     }
0708 
0709     personElement = pronounElement.firstChildElement(KVTML_GRAMMATICAL_NUMBER[2]);
0710     if (!personElement.isNull()) {
0711         readPersonalPronounChild(personElement, pronoun, KEduVocWordFlag::Plural);
0712     }
0713     return true;
0714 }
0715 
0716 bool KEduVocKvtml2Reader::readPersonalPronounChild(QDomElement &personElement, KEduVocPersonalPronoun &pronoun, KEduVocWordFlags number)
0717 {
0718     QMap<int, KEduVocWordFlag::Flags> persons;
0719     persons[0] = KEduVocWordFlag::First;
0720     persons[1] = KEduVocWordFlag::Second;
0721     persons[2] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Masculine);
0722     persons[3] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Feminine);
0723     persons[4] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Neuter);
0724 
0725     for (int person = 0; person < 5; person++) {
0726         QDomElement currentElement = personElement.firstChildElement(KVTML_GRAMMATICAL_PERSON[person]);
0727         pronoun.setPersonalPronoun(currentElement.text(), persons[person] | number);
0728     }
0729 
0730     return true;
0731 }
0732 
0733 #include "moc_keduvockvtml2reader.cpp"