File indexing completed on 2024-04-21 03:48:19
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 Frederik Gladhorn <frederik.gladhorn@kdemail.net> 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "keduvockvtmlreader.h" 0011 0012 #include <KLocalizedString> 0013 #include <QIODevice> 0014 #include <QTextStream> 0015 0016 #include <QDebug> 0017 #include <QLocale> 0018 0019 #include "keduvoccommon_p.h" 0020 #include "keduvoclesson.h" 0021 #include "keduvocwordtype.h" 0022 #include "kvtmldefs.h" 0023 0024 KEduVocKvtmlReader::KEduVocKvtmlReader(QIODevice &file) 0025 : m_inputFile(&file) 0026 { 0027 m_errorMessage = QLatin1String(""); 0028 qDebug() << "KEduVocKvtmlReader for kvtml version 1 files started."; 0029 } 0030 0031 bool KEduVocKvtmlReader::isParsable() 0032 { 0033 QTextStream ts(m_inputFile); 0034 QString line1(ts.readLine()); 0035 QString line2(ts.readLine()); 0036 0037 m_inputFile->seek(0); 0038 return ((line1.startsWith(QLatin1String("<?xml"))) && (line2.indexOf(KV_DOCTYPE, 0) > 0)); 0039 } 0040 0041 KEduVocDocument::ErrorCode KEduVocKvtmlReader::read(KEduVocDocument &doc) 0042 { 0043 m_doc = &doc; 0044 m_cols = 0; 0045 m_lines = 0; 0046 0047 QDomDocument domDoc(QStringLiteral("KEduVocDocument")); 0048 0049 if (!domDoc.setContent(m_inputFile, &m_errorMessage)) 0050 return KEduVocDocument::InvalidXml; 0051 0052 QDomElement domElementKvtml = domDoc.documentElement(); 0053 if (domElementKvtml.tagName() != KV_DOCTYPE) { 0054 m_errorMessage = i18n("This is not a KDE Vocabulary document."); 0055 return KEduVocDocument::FileTypeUnknown; 0056 } 0057 0058 //------------------------------------------------------------------------- 0059 // Attributes 0060 //------------------------------------------------------------------------- 0061 0062 QDomAttr documentAttribute; 0063 documentAttribute = domElementKvtml.attributeNode(KV_ENCODING); 0064 if (!documentAttribute.isNull()) { 0065 // TODO handle old encodings 0066 // Qt DOM API autodetects encoding, so is there anything to do ? 0067 } 0068 0069 documentAttribute = domElementKvtml.attributeNode(KV_TITLE); 0070 if (!documentAttribute.isNull()) 0071 m_doc->setTitle(documentAttribute.value()); 0072 0073 documentAttribute = domElementKvtml.attributeNode(KV_AUTHOR); 0074 if (!documentAttribute.isNull()) 0075 m_doc->setAuthor(documentAttribute.value()); 0076 0077 documentAttribute = domElementKvtml.attributeNode(KV_LICENSE); 0078 if (!documentAttribute.isNull()) 0079 m_doc->setLicense(documentAttribute.value()); 0080 0081 documentAttribute = domElementKvtml.attributeNode(KV_DOC_REM); 0082 if (!documentAttribute.isNull()) 0083 m_doc->setDocumentComment(documentAttribute.value()); 0084 0085 documentAttribute = domElementKvtml.attributeNode(KV_GENERATOR); 0086 if (!documentAttribute.isNull()) { 0087 m_doc->setGenerator(documentAttribute.value()); 0088 int pos = m_doc->generator().lastIndexOf(KVD_VERS_PREFIX); 0089 if (pos >= 0) 0090 m_doc->setVersion(m_doc->generator().remove(0, pos + 2)); 0091 } 0092 0093 documentAttribute = domElementKvtml.attributeNode(KV_COLS); 0094 if (!documentAttribute.isNull()) 0095 m_cols = documentAttribute.value().toInt(); /// currently not used anywhere 0096 0097 documentAttribute = domElementKvtml.attributeNode(KV_LINES); 0098 if (!documentAttribute.isNull()) 0099 m_lines = documentAttribute.value().toInt(); 0100 0101 //------------------------------------------------------------------------- 0102 // Children 0103 //------------------------------------------------------------------------- 0104 0105 bool result = readBody(domElementKvtml); // read vocabulary 0106 0107 return result ? KEduVocDocument::NoError : KEduVocDocument::FileReaderFailed; 0108 } 0109 0110 bool KEduVocKvtmlReader::readBody(QDomElement &domElementParent) 0111 { 0112 bool result = false; 0113 0114 QDomElement currentElement; 0115 0116 currentElement = domElementParent.firstChildElement(KV_LESS_GRP); 0117 if (!currentElement.isNull()) { 0118 result = readLesson(currentElement); 0119 if (!result) 0120 return false; 0121 } 0122 0123 currentElement = domElementParent.firstChildElement(KV_ARTICLE_GRP); 0124 if (!currentElement.isNull()) { 0125 result = readArticle(currentElement); 0126 if (!result) 0127 return false; 0128 } 0129 0130 currentElement = domElementParent.firstChildElement(KV_CONJUG_GRP); 0131 if (!currentElement.isNull()) { 0132 int count = 0; 0133 0134 QDomElement domElementConjugChild = currentElement.firstChildElement(KV_CON_ENTRY); 0135 while (!domElementConjugChild.isNull()) { 0136 QString lang; 0137 QDomAttr domAttrLang = domElementConjugChild.attributeNode(KV_LANG); // "l" 0138 // make sure, the identifier is there 0139 if (!addLanguage(count, domAttrLang.value())) { 0140 return false; 0141 } 0142 0143 KEduVocPersonalPronoun pronouns; 0144 if (!readPersonalPronouns(domElementConjugChild, pronouns)) { 0145 return false; 0146 } 0147 m_doc->identifier(count).setPersonalPronouns(pronouns); 0148 0149 count++; 0150 0151 domElementConjugChild = domElementConjugChild.nextSiblingElement(KV_CON_ENTRY); 0152 } 0153 } 0154 0155 // initialize the list of predefined types 0156 m_compability.setupWordTypes(m_doc->wordTypeContainer()); 0157 0158 currentElement = domElementParent.firstChildElement(KV_TYPE_GRP); 0159 if (!currentElement.isNull()) { 0160 result = readType(currentElement); 0161 if (!result) 0162 return false; 0163 } 0164 0165 currentElement = domElementParent.firstChildElement(KV_TENSE_GRP); 0166 if (!currentElement.isNull()) { 0167 result = readTense(currentElement); 0168 if (!result) 0169 return false; 0170 } 0171 0172 QDomNodeList entryList = domElementParent.elementsByTagName(KV_EXPR); 0173 if (entryList.length() <= 0) 0174 return false; 0175 0176 for (int i = 0; i < entryList.count(); ++i) { 0177 currentElement = entryList.item(i).toElement(); 0178 if (currentElement.parentNode() == domElementParent) { 0179 result = readExpression(currentElement); 0180 if (!result) 0181 return false; 0182 } 0183 } 0184 0185 for (int i = 0; i < m_doc->identifierCount(); i++) { 0186 m_doc->identifier(i).setTenseList(m_compability.documentTenses()); 0187 } 0188 0189 return true; 0190 } 0191 0192 bool KEduVocKvtmlReader::readLesson(QDomElement &domElementParent) 0193 { 0194 QString s; 0195 QDomAttr attribute; 0196 QDomElement currentElement; 0197 0198 //------------------------------------------------------------------------- 0199 // Children 0200 //------------------------------------------------------------------------- 0201 0202 QDomNodeList entryList = domElementParent.elementsByTagName(KV_LESS_DESC); 0203 if (entryList.length() <= 0) 0204 return false; 0205 0206 for (int i = 0; i < entryList.count(); ++i) { 0207 currentElement = entryList.item(i).toElement(); 0208 if (currentElement.parentNode() == domElementParent) { 0209 int no = -1; 0210 0211 attribute = currentElement.attributeNode(KV_LESS_NO); 0212 if (!attribute.isNull()) { 0213 no = attribute.value().toInt(); 0214 } 0215 0216 bool inQuery = false; 0217 attribute = currentElement.attributeNode(KV_LESS_QUERY); 0218 if (!attribute.isNull()) { 0219 inQuery = (attribute.value().toInt() != 0); 0220 } 0221 0222 s = currentElement.text(); 0223 KEduVocLesson *lesson = new KEduVocLesson(s, m_doc->lesson()); 0224 lesson->setInPractice(inQuery); 0225 m_doc->lesson()->appendChildContainer(lesson); 0226 if (m_doc->lesson()->childContainerCount() != no - 1) { 0227 qDebug() << "Warning! Lesson order may be confused. Are all lessons in order in the file?"; 0228 } 0229 } 0230 } 0231 0232 return true; 0233 } 0234 0235 bool KEduVocKvtmlReader::readArticle(QDomElement &domElementParent) 0236 /* 0237 <article> 0238 <e l="de"> lang determines also lang order in entries !! 0239 <fi>eine</fi> which must NOT differ 0240 <fd>die</fd> 0241 <mi>ein</mi> 0242 <md>der</md> 0243 <ni>ein</ni> 0244 <nd>das</nd> 0245 </e> 0246 </article> 0247 */ 0248 { 0249 QString s; 0250 QDomAttr attribute; 0251 QDomElement currentElement; 0252 QDomElement article; 0253 0254 QDomNodeList entryList = domElementParent.elementsByTagName(KV_ART_ENTRY); 0255 if (entryList.length() <= 0) 0256 return false; 0257 0258 for (int i = 0; i < entryList.count(); ++i) { 0259 // qDebug() << "KEduVocKvtmlReader::readArticle() read " << entryList.count() << " articles. "; 0260 currentElement = entryList.item(i).toElement(); 0261 if (currentElement.parentNode() == domElementParent) { 0262 QString lang; 0263 attribute = currentElement.attributeNode(KV_LANG); 0264 0265 if (!addLanguage(i, attribute.value())) { 0266 return false; 0267 } 0268 0269 //--------- 0270 // Children 0271 0272 QString fem_def = QLatin1String(""); 0273 QString mal_def = QLatin1String(""); 0274 QString nat_def = QLatin1String(""); 0275 QString fem_indef = QLatin1String(""); 0276 QString mal_indef = QLatin1String(""); 0277 QString nat_indef = QLatin1String(""); 0278 0279 article = currentElement.firstChildElement(KV_ART_FD); 0280 if (!article.isNull()) { 0281 fem_def = article.text(); 0282 if (fem_def.isNull()) 0283 fem_def = QLatin1String(""); 0284 } 0285 0286 article = currentElement.firstChildElement(KV_ART_FI); 0287 if (!article.isNull()) { 0288 fem_indef = article.text(); 0289 if (fem_indef.isNull()) 0290 fem_indef = QLatin1String(""); 0291 } 0292 0293 article = currentElement.firstChildElement(KV_ART_MD); 0294 if (!article.isNull()) { 0295 mal_def = article.text(); 0296 if (mal_def.isNull()) 0297 mal_def = QLatin1String(""); 0298 } 0299 0300 article = currentElement.firstChildElement(KV_ART_MI); 0301 if (!article.isNull()) { 0302 mal_indef = article.text(); 0303 if (mal_indef.isNull()) 0304 mal_indef = QLatin1String(""); 0305 } 0306 0307 article = currentElement.firstChildElement(KV_ART_ND); 0308 if (!article.isNull()) { 0309 nat_def = article.text(); 0310 if (nat_def.isNull()) 0311 nat_def = QLatin1String(""); 0312 } 0313 0314 article = currentElement.firstChildElement(KV_ART_NI); 0315 if (!article.isNull()) { 0316 nat_indef = article.text(); 0317 if (nat_indef.isNull()) 0318 nat_indef = QLatin1String(""); 0319 } 0320 0321 KEduVocArticle article; 0322 article.setArticle(mal_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Masculine); 0323 article.setArticle(fem_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Feminine); 0324 article.setArticle(nat_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Neuter); 0325 article.setArticle(mal_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Masculine); 0326 article.setArticle(fem_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Feminine); 0327 article.setArticle(nat_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Neuter); 0328 m_doc->identifier(i).setArticle(article); 0329 } 0330 } 0331 0332 return true; 0333 } 0334 0335 bool KEduVocKvtmlReader::readTranslationConjugations(QDomElement &domElementParent, KEduVocTranslation *translation) 0336 { 0337 QString tense; 0338 0339 QDomElement domElementConjugChild = domElementParent.firstChildElement(KV_CON_TYPE); 0340 while (!domElementConjugChild.isNull()) { 0341 // "n" == is the type is the tense 0342 QDomAttr domAttrLang = domElementConjugChild.attributeNode(KV_CON_NAME); 0343 QString oldShortTense = domAttrLang.value(); 0344 0345 tense = m_compability.tenseFromKvtml1(oldShortTense); 0346 KEduVocConjugation conjugation; 0347 readConjugation(domElementConjugChild, conjugation); 0348 translation->setConjugation(tense, conjugation); 0349 0350 domElementConjugChild = domElementConjugChild.nextSiblingElement(KV_CON_TYPE); 0351 } // while -> next tense, count++ 0352 return true; 0353 } 0354 0355 bool KEduVocKvtmlReader::readConjugation(QDomElement &domElementParent, KEduVocConjugation &conjugation) 0356 /* 0357 <conjugation> used in header for definition of "prefix" 0358 <e l="de"> lang determines also lang order in entries !! 0359 <s1>I</s1> which must NOT differ 0360 <s2>you<2> 0361 <s3f>he</s3f> 0362 <s3m>she</s3m> 0363 <s3n>it</s3n> 0364 <p1>we</p1> 0365 <p2>you</p2> 0366 <p3f>they</p3f> 0367 <p3m>they</p3m> 0368 <p3n>they</p3n> 0369 </e> 0370 </conjugation> 0371 0372 <conjugation> and in entry for definition of tenses of (irreg.) verbs 0373 <t n="sipa"> 0374 <s1>go</s1> 0375 <s2>go</s2> 0376 <s3f>goes</s3f> 0377 <s3m>goes</s3m> 0378 <s3n>goes</s3n> 0379 <p1>go</p1> 0380 <p2>go</p2> 0381 <p3f>go</p3f> 0382 <p3m>go</p3m> 0383 <p3n>go</p3n> 0384 </t> 0385 </conjugation> 0386 */ 0387 { 0388 // QString s; 0389 bool p3_common; 0390 bool s3_common; 0391 QString pers1_sing; 0392 QString pers2_sing; 0393 QString pers3_m_sing; 0394 QString pers3_f_sing; 0395 QString pers3_n_sing; 0396 QString pers1_plur; 0397 QString pers2_plur; 0398 QString pers3_m_plur; 0399 QString pers3_f_plur; 0400 QString pers3_n_plur; 0401 0402 p3_common = false; 0403 s3_common = false; 0404 0405 // get the individual entries for persons... 0406 QDomElement domElementConjugGrandChild = domElementParent.firstChild().toElement(); 0407 while (!domElementConjugGrandChild.isNull()) { 0408 if (domElementConjugGrandChild.tagName() == KV_CON_P1S) { 0409 pers1_sing = domElementConjugGrandChild.text(); 0410 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2S) { 0411 pers2_sing = domElementConjugGrandChild.text(); 0412 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SF) { 0413 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON); 0414 if (!domAttrCommon.isNull()) 0415 s3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails 0416 pers3_f_sing = domElementConjugGrandChild.text(); 0417 0418 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SM) { 0419 pers3_m_sing = domElementConjugGrandChild.text(); 0420 0421 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SN) { 0422 pers3_n_sing = domElementConjugGrandChild.text(); 0423 0424 } else if (domElementConjugGrandChild.tagName() == KV_CON_P1P) { 0425 pers1_plur = domElementConjugGrandChild.text(); 0426 0427 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2P) { 0428 pers2_plur = domElementConjugGrandChild.text(); 0429 0430 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PF) { 0431 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON); 0432 if (!domAttrCommon.isNull()) 0433 p3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails 0434 0435 pers3_f_plur = domElementConjugGrandChild.text(); 0436 0437 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PM) { 0438 pers3_m_plur = domElementConjugGrandChild.text(); 0439 0440 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PN) { 0441 pers3_n_plur = domElementConjugGrandChild.text(); 0442 0443 } else { 0444 return false; 0445 } 0446 0447 domElementConjugGrandChild = domElementConjugGrandChild.nextSibling().toElement(); 0448 } // while - probably to be sure, because the persons could be in any order. 0449 // I guess this goes over only one set, such as: 0450 // <s1>traigo</s1><s2>traes</s2><s3fcommon="1">trae</s3f> 0451 // <p1>traemos</p1><p2>traéis</p2><p3f common="1">traen</p3f> 0452 // until no elements are left in that soup. 0453 0454 // now set the data: [count] - number of conjug? 0455 // type - the tense? 0456 // finally the person 0457 0458 const KEduVocWordFlags numS = KEduVocWordFlag::Singular; 0459 const KEduVocWordFlags numP = KEduVocWordFlag::Plural; 0460 0461 conjugation.setConjugation(pers1_sing, KEduVocWordFlag::First | numS); 0462 conjugation.setConjugation(pers2_sing, KEduVocWordFlag::Second | numS); 0463 conjugation.setConjugation(pers1_plur, KEduVocWordFlag::First | numP); 0464 conjugation.setConjugation(pers2_plur, KEduVocWordFlag::Second | numP); 0465 0466 if (s3_common) { 0467 conjugation.setConjugation(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Singular); 0468 } else { 0469 conjugation.setConjugation(pers3_m_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | KEduVocWordFlag::Singular); 0470 conjugation.setConjugation(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | KEduVocWordFlag::Singular); 0471 conjugation.setConjugation(pers3_n_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Singular); 0472 } 0473 0474 if (p3_common) { 0475 conjugation.setConjugation(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Plural); 0476 } else { 0477 conjugation.setConjugation(pers3_m_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | KEduVocWordFlag::Plural); 0478 conjugation.setConjugation(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | KEduVocWordFlag::Plural); 0479 conjugation.setConjugation(pers3_n_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Plural); 0480 } 0481 0482 return true; 0483 } 0484 0485 bool KEduVocKvtmlReader::readPersonalPronouns(QDomElement &domElementParent, KEduVocPersonalPronoun &pronouns) 0486 { 0487 // QString s; 0488 bool p3_common; 0489 bool s3_common; 0490 QString pers1_sing; 0491 QString pers2_sing; 0492 QString pers3_m_sing; 0493 QString pers3_f_sing; 0494 QString pers3_n_sing; 0495 QString pers1_plur; 0496 QString pers2_plur; 0497 QString pers3_m_plur; 0498 QString pers3_f_plur; 0499 QString pers3_n_plur; 0500 0501 p3_common = false; 0502 s3_common = false; 0503 0504 // get the individual entries for persons... 0505 QDomElement domElementConjugGrandChild = domElementParent.firstChild().toElement(); 0506 while (!domElementConjugGrandChild.isNull()) { 0507 if (domElementConjugGrandChild.tagName() == KV_CON_P1S) { 0508 pers1_sing = domElementConjugGrandChild.text(); 0509 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2S) { 0510 pers2_sing = domElementConjugGrandChild.text(); 0511 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SF) { 0512 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON); 0513 if (!domAttrCommon.isNull()) 0514 s3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails 0515 pers3_f_sing = domElementConjugGrandChild.text(); 0516 0517 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SM) { 0518 pers3_m_sing = domElementConjugGrandChild.text(); 0519 0520 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SN) { 0521 pers3_n_sing = domElementConjugGrandChild.text(); 0522 0523 } else if (domElementConjugGrandChild.tagName() == KV_CON_P1P) { 0524 pers1_plur = domElementConjugGrandChild.text(); 0525 0526 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2P) { 0527 pers2_plur = domElementConjugGrandChild.text(); 0528 0529 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PF) { 0530 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON); 0531 if (!domAttrCommon.isNull()) 0532 p3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails 0533 0534 pers3_f_plur = domElementConjugGrandChild.text(); 0535 0536 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PM) { 0537 pers3_m_plur = domElementConjugGrandChild.text(); 0538 0539 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PN) { 0540 pers3_n_plur = domElementConjugGrandChild.text(); 0541 0542 } else { 0543 return false; 0544 } 0545 0546 domElementConjugGrandChild = domElementConjugGrandChild.nextSibling().toElement(); 0547 } // while - probably to be sure, because the persons could be in any order. 0548 // I guess this goes over only one set, such as: 0549 // <s1>traigo</s1><s2>traes</s2><s3fcommon="1">trae</s3f> 0550 // <p1>traemos</p1><p2>traéis</p2><p3f common="1">traen</p3f> 0551 // until no elements are left in that soup. 0552 0553 // now set the data: [count] - number of conjug? 0554 // type - the tense? 0555 // finally the person 0556 0557 KEduVocWordFlags numS = KEduVocWordFlag::Singular; 0558 pronouns.setMaleFemaleDifferent(false); 0559 pronouns.setPersonalPronoun(pers1_sing, KEduVocWordFlag::First | numS); 0560 pronouns.setPersonalPronoun(pers2_sing, KEduVocWordFlag::Second | numS); 0561 0562 // used to have common in female 0563 if (s3_common) { 0564 pronouns.setPersonalPronoun(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numS); 0565 } else { 0566 pronouns.setPersonalPronoun(pers3_m_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | numS); 0567 pronouns.setPersonalPronoun(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | numS); 0568 pronouns.setPersonalPronoun(pers3_n_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numS); 0569 pronouns.setMaleFemaleDifferent(true); 0570 } 0571 0572 KEduVocWordFlags numP = KEduVocWordFlag::Plural; 0573 0574 pronouns.setPersonalPronoun(pers1_plur, KEduVocWordFlag::First | numP); 0575 pronouns.setPersonalPronoun(pers2_plur, KEduVocWordFlag::Second | numP); 0576 if (p3_common) { 0577 pronouns.setPersonalPronoun(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numP); 0578 } else { 0579 pronouns.setPersonalPronoun(pers3_m_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | numP); 0580 pronouns.setPersonalPronoun(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | numP); 0581 pronouns.setPersonalPronoun(pers3_n_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numP); 0582 pronouns.setMaleFemaleDifferent(true); 0583 } 0584 0585 return true; 0586 } 0587 0588 bool KEduVocKvtmlReader::readType(QDomElement &domElementParent) 0589 { 0590 QString s; 0591 QDomElement currentElement; 0592 0593 QDomNodeList entryList = domElementParent.elementsByTagName(KV_TYPE_DESC); 0594 if (entryList.length() <= 0) 0595 return false; 0596 0597 for (int i = 0; i < entryList.count(); ++i) { 0598 currentElement = entryList.item(i).toElement(); 0599 if (currentElement.parentNode() == domElementParent) { 0600 // We need to even add empty elements since the old system relied on 0601 // the order. So "type1" "" "type2" should be just like that. 0602 0603 qDebug() << "Adding old self defined type: " << currentElement.text(); 0604 // add the type to the list of available types 0605 KEduVocWordType *type = new KEduVocWordType(currentElement.text(), m_doc->wordTypeContainer()); 0606 m_doc->wordTypeContainer()->appendChildContainer(type); 0607 0608 // from this the #1 are transformed to something sensible again 0609 m_oldSelfDefinedTypes.append(currentElement.text()); 0610 } 0611 } 0612 0613 return true; 0614 } 0615 0616 bool KEduVocKvtmlReader::readTense(QDomElement &domElementParent) 0617 { 0618 QDomElement currentElement; 0619 0620 currentElement = domElementParent.firstChildElement(KV_TENSE_DESC); 0621 while (!currentElement.isNull()) { 0622 qDebug() << "Reading user defined tense description: " << currentElement.text(); 0623 m_compability.addUserdefinedTense(currentElement.text()); 0624 currentElement = currentElement.nextSiblingElement(KV_TENSE_DESC); 0625 } 0626 return true; 0627 } 0628 0629 bool KEduVocKvtmlReader::readComparison(QDomElement &domElementParent, KEduVocTranslation *translation) 0630 /* 0631 <comparison> 0632 <l1>good</l1> --- this one is dead as it always has to be the word itself 0633 <l2>better</l2> 0634 <l3>best</l3> 0635 </comparison> 0636 */ 0637 { 0638 QDomElement currentElement; 0639 0640 currentElement = domElementParent.firstChildElement(KV_COMP_L2); 0641 translation->setComparativeForm(currentElement.text()); 0642 0643 currentElement = domElementParent.firstChildElement(KV_COMP_L3); 0644 translation->setSuperlativeForm(currentElement.text()); 0645 0646 return true; 0647 } 0648 0649 bool KEduVocKvtmlReader::readMultipleChoice(QDomElement &domElementParent, KEduVocTranslation *translation) 0650 /* 0651 <multiplechoice> 0652 <mc1>good</mc1> 0653 <mc2>better</mc2> 0654 <mc3>best</mc3> 0655 <mc4>best 2</mc4> 0656 <mc5>best 3</mc5> 0657 </multiplechoice> 0658 */ 0659 0660 { 0661 QDomElement currentElement; 0662 QStringList choices = translation->getMultipleChoice(); 0663 0664 currentElement = domElementParent.firstChildElement(KV_MC_1); 0665 if (!currentElement.isNull()) { 0666 choices.append(currentElement.text()); 0667 } 0668 0669 currentElement = domElementParent.firstChildElement(KV_MC_2); 0670 if (!currentElement.isNull()) { 0671 choices.append(currentElement.text()); 0672 } 0673 0674 currentElement = domElementParent.firstChildElement(KV_MC_3); 0675 if (!currentElement.isNull()) { 0676 choices.append(currentElement.text()); 0677 } 0678 0679 currentElement = domElementParent.firstChildElement(KV_MC_4); 0680 if (!currentElement.isNull()) { 0681 choices.append(currentElement.text()); 0682 } 0683 0684 currentElement = domElementParent.firstChildElement(KV_MC_5); 0685 if (!currentElement.isNull()) { 0686 choices.append(currentElement.text()); 0687 } 0688 0689 translation->setMultipleChoice(choices); 0690 0691 return true; 0692 } 0693 0694 bool KEduVocKvtmlReader::readExpressionChildAttributes(QDomElement &domElementExpressionChild, 0695 QString &lang, 0696 grade_t &grade, 0697 grade_t &rev_grade, 0698 int &count, 0699 int &rev_count, 0700 QDateTime &date, 0701 QDateTime &rev_date, 0702 QString &remark, 0703 int &bcount, 0704 int &rev_bcount, 0705 QString &query_id, 0706 QString &pronunciation, 0707 int &width, 0708 QString &type, 0709 QString &faux_ami_f, 0710 QString &faux_ami_t, 0711 QString &synonym, 0712 QString &example, 0713 QString &antonym, 0714 QSet<QString> &usages, 0715 QString ¶phrase) 0716 { 0717 Q_UNUSED(usages) 0718 int pos; 0719 QDomAttr attribute; 0720 0721 lang = QLatin1String(""); 0722 attribute = domElementExpressionChild.attributeNode(KV_LANG); 0723 if (!attribute.isNull()) 0724 lang = attribute.value(); 0725 0726 width = -1; 0727 attribute = domElementExpressionChild.attributeNode(KV_SIZEHINT); 0728 if (!attribute.isNull()) 0729 width = attribute.value().toInt(); 0730 0731 grade = KV_NORM_GRADE; 0732 rev_grade = KV_NORM_GRADE; 0733 attribute = domElementExpressionChild.attributeNode(KV_GRADE); 0734 if (!attribute.isNull()) { 0735 QString s = attribute.value(); 0736 if ((pos = s.indexOf(';')) >= 1) { 0737 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0738 grade = s.leftRef(pos).toInt(); 0739 rev_grade = s.midRef(pos + 1, s.length()).toInt(); 0740 #else 0741 grade = QStringView(s).left(pos).toInt(); 0742 rev_grade = QStringView(s).mid(pos + 1, s.length()).toInt(); 0743 #endif 0744 } else 0745 grade = s.toInt(); 0746 } 0747 0748 count = 0; 0749 rev_count = 0; 0750 attribute = domElementExpressionChild.attributeNode(KV_COUNT); 0751 if (!attribute.isNull()) { 0752 QString s = attribute.value(); 0753 if ((pos = s.indexOf(';')) >= 1) { 0754 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0755 count = s.leftRef(pos).toInt(); 0756 rev_count = s.midRef(pos + 1, s.length()).toInt(); 0757 #else 0758 count = QStringView(s).left(pos).toInt(); 0759 rev_count = QStringView(s).mid(pos + 1, s.length()).toInt(); 0760 #endif 0761 } else 0762 count = s.toInt(); 0763 } 0764 0765 bcount = 0; 0766 rev_bcount = 0; 0767 attribute = domElementExpressionChild.attributeNode(KV_BAD); 0768 if (!attribute.isNull()) { 0769 QString s = attribute.value(); 0770 if ((pos = s.indexOf(';')) >= 1) { 0771 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0772 bcount = s.leftRef(pos).toInt(); 0773 rev_bcount = s.midRef(pos + 1, s.length()).toInt(); 0774 #else 0775 bcount = QStringView(s).left(pos).toInt(); 0776 rev_bcount = QStringView(s).mid(pos + 1, s.length()).toInt(); 0777 #endif 0778 } else 0779 bcount = s.toInt(); 0780 } 0781 0782 date = QDateTime::fromSecsSinceEpoch(0); 0783 rev_date = QDateTime::fromSecsSinceEpoch(0); 0784 attribute = domElementExpressionChild.attributeNode(KV_DATE); 0785 if (!attribute.isNull()) { 0786 QString s = attribute.value(); 0787 if ((pos = s.indexOf(';')) >= 1) { 0788 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0789 date = QDateTime::fromSecsSinceEpoch(s.leftRef(pos).toInt()); 0790 rev_date.setTime_t(s.midRef(pos + 1, s.length()).toInt()); 0791 #else 0792 date = QDateTime::fromSecsSinceEpoch(QStringView(s).left(pos).toInt()); 0793 rev_date = QDateTime::fromSecsSinceEpoch(QStringView(s).mid(pos + 1, s.length()).toInt()); 0794 #endif 0795 } else 0796 date = QDateTime::fromSecsSinceEpoch(s.toInt()); 0797 } 0798 0799 attribute = domElementExpressionChild.attributeNode(KV_DATE2); 0800 if (!attribute.isNull()) { 0801 // this format is deprecated and ignored. 0802 } 0803 0804 remark = QLatin1String(""); 0805 attribute = domElementExpressionChild.attributeNode(KV_REMARK); 0806 if (!attribute.isNull()) 0807 remark = attribute.value(); 0808 0809 faux_ami_f = QLatin1String(""); 0810 attribute = domElementExpressionChild.attributeNode(KV_FAUX_AMI_F); 0811 if (!attribute.isNull()) 0812 faux_ami_f = attribute.value(); 0813 0814 faux_ami_t = QLatin1String(""); 0815 attribute = domElementExpressionChild.attributeNode(KV_FAUX_AMI_T); 0816 if (!attribute.isNull()) 0817 faux_ami_t = attribute.value(); 0818 0819 synonym = QLatin1String(""); 0820 attribute = domElementExpressionChild.attributeNode(KV_SYNONYM); 0821 if (!attribute.isNull()) 0822 synonym = attribute.value(); 0823 0824 example = QLatin1String(""); 0825 attribute = domElementExpressionChild.attributeNode(KV_EXAMPLE); 0826 if (!attribute.isNull()) 0827 example = attribute.value(); 0828 0829 paraphrase = QLatin1String(""); 0830 attribute = domElementExpressionChild.attributeNode(KV_PARAPHRASE); 0831 if (!attribute.isNull()) 0832 paraphrase = attribute.value(); 0833 0834 antonym = QLatin1String(""); 0835 attribute = domElementExpressionChild.attributeNode(KV_ANTONYM); 0836 if (!attribute.isNull()) 0837 antonym = attribute.value(); 0838 0839 // this is all done by reference - so we have to care about "type" :( 0840 attribute = domElementExpressionChild.attributeNode(KV_EXPRTYPE); 0841 if (!attribute.isNull()) { 0842 type = attribute.value(); 0843 } 0844 0845 pronunciation = QLatin1String(""); 0846 attribute = domElementExpressionChild.attributeNode(KV_PRONUNCE); 0847 if (!attribute.isNull()) 0848 pronunciation = attribute.value(); 0849 0850 query_id = QLatin1String(""); 0851 attribute = domElementExpressionChild.attributeNode(KV_QUERY); 0852 if (!attribute.isNull()) 0853 query_id = attribute.value(); 0854 0855 return true; 0856 } 0857 0858 bool KEduVocKvtmlReader::readExpression(QDomElement &domElementParent) 0859 { 0860 grade_t grade; 0861 grade_t r_grade; 0862 int qcount; 0863 int r_qcount; 0864 int bcount; 0865 int r_bcount; 0866 QString remark; 0867 QString pronunciation; 0868 QDateTime qdate; 0869 QDateTime r_qdate; 0870 // bool inquery; 0871 bool active; 0872 QString lang; 0873 QString textstr; 0874 QString q_org; 0875 QString q_trans; 0876 QString query_id; 0877 int width; 0878 QString type; 0879 QString faux_ami_f; 0880 QString faux_ami_t; 0881 QString synonym; 0882 QString example; 0883 QString antonym; 0884 QSet<QString> usage; 0885 QString paraphrase; 0886 0887 QDomAttr attribute; 0888 QDomElement currentElement; 0889 QDomElement currentChild; 0890 0891 int lessonNumber = -1; 0892 0893 //------------------------------------------------------------------------- 0894 // Attributes 0895 //------------------------------------------------------------------------- 0896 0897 attribute = domElementParent.attributeNode(KV_LESS_MEMBER); 0898 if (!attribute.isNull()) { 0899 // we start counting from 0 in new documents 0900 lessonNumber = attribute.value().toInt() - 1; 0901 if (lessonNumber > m_doc->lesson()->childContainerCount()) { 0902 ///@todo can this happen? does it need a while loop? 0903 // it's from a lesson that hasn't been added yet 0904 // so make sure this lesson is in the document 0905 qDebug() << "Warning: lesson > m_doc->lessonCount() in readExpression."; 0906 0907 KEduVocLesson *lesson = new KEduVocLesson(i18nc("A generic name for a new lesson and its number.", "Lesson %1", lessonNumber), m_doc->lesson()); 0908 m_doc->lesson()->appendChildContainer(lesson); 0909 } 0910 } 0911 0912 attribute = domElementParent.attributeNode(KV_SELECTED); 0913 // if ( !attribute.isNull() ) 0914 // inquery = attribute.value() == "1" ? true : false; 0915 // else 0916 // inquery = false; 0917 0918 attribute = domElementParent.attributeNode(KV_INACTIVE); 0919 if (!attribute.isNull()) 0920 active = attribute.value() == QLatin1Char('1') ? false : true; 0921 else 0922 active = true; 0923 0924 // this is all done by reference - so we have to care about "type" :( 0925 attribute = domElementParent.attributeNode(KV_EXPRTYPE); 0926 if (!attribute.isNull()) { 0927 type = attribute.value(); 0928 } 0929 0930 //------------------------------------------------------------------------- 0931 // Children 'Translation' 0932 //------------------------------------------------------------------------- 0933 0934 // QDomNodeList translationList = domElementParent.elementsByTagName(KV_TRANS); 0935 0936 // count which translation we are on 0937 int i = 0; 0938 0939 // kvtml 1: we always have an original element (required) 0940 currentElement = domElementParent.firstChildElement(KV_ORG); 0941 if (currentElement.isNull()) { // sanity check 0942 m_errorMessage = i18n("Data for original language missing"); 0943 return false; 0944 } 0945 0946 KEduVocExpression *entry = nullptr; 0947 0948 while (!currentElement.isNull()) { 0949 //----------- 0950 // Attributes 0951 //----------- 0952 0953 // read attributes - the order of the query grades is interchanged! 0954 if (i == 0 0955 && !readExpressionChildAttributes(currentElement, 0956 lang, 0957 grade, 0958 r_grade, 0959 qcount, 0960 r_qcount, 0961 qdate, 0962 r_qdate, 0963 remark, 0964 bcount, 0965 r_bcount, 0966 query_id, 0967 pronunciation, 0968 width, 0969 type, 0970 faux_ami_t, 0971 faux_ami_f, 0972 synonym, 0973 example, 0974 antonym, 0975 usage, 0976 paraphrase)) { 0977 return false; 0978 } 0979 0980 if (i != 0 0981 && !readExpressionChildAttributes(currentElement, 0982 lang, 0983 grade, 0984 r_grade, 0985 qcount, 0986 r_qcount, 0987 qdate, 0988 r_qdate, 0989 remark, 0990 bcount, 0991 r_bcount, 0992 query_id, 0993 pronunciation, 0994 width, 0995 type, 0996 faux_ami_f, 0997 faux_ami_t, 0998 synonym, 0999 example, 1000 antonym, 1001 usage, 1002 paraphrase)) { 1003 return false; 1004 } 1005 1006 //--------- 1007 // Children 1008 1009 textstr = currentElement.lastChild().toText().data(); 1010 1011 if (i == 0) { 1012 entry = new KEduVocExpression(textstr); 1013 entry->setActive(active); 1014 if (lessonNumber != -1) { 1015 static_cast<KEduVocLesson *>(m_doc->lesson()->childContainer(lessonNumber))->appendEntry(entry); 1016 } else { 1017 m_doc->lesson()->appendEntry(entry); 1018 } 1019 } else { 1020 entry->setTranslation(i, textstr); 1021 } 1022 1023 if (m_doc->lesson()->entries(KEduVocLesson::Recursive).count() == 1) { // this is because in kvtml the languages are saved in the FIRST ENTRY ONLY. 1024 // new translation 1025 if (!addLanguage(i, lang)) { 1026 return false; 1027 } 1028 } 1029 1030 // better make sure, translation(i) already exists... 1031 currentChild = currentElement.firstChildElement(KV_CONJUG_GRP); 1032 if (!currentChild.isNull()) { 1033 if (!readTranslationConjugations(currentChild, entry->translation(i))) { 1034 return false; 1035 } 1036 } 1037 1038 currentChild = currentElement.firstChildElement(KV_MULTIPLECHOICE_GRP); 1039 if (!currentChild.isNull()) { 1040 if (!readMultipleChoice(currentChild, entry->translation(i))) { 1041 return false; 1042 } 1043 } 1044 1045 currentChild = currentElement.firstChildElement(KV_COMPARISON_GRP); 1046 if (!currentChild.isNull()) { 1047 if (!readComparison(currentChild, entry->translation(i))) { 1048 return false; 1049 } 1050 } 1051 1052 if (!type.isEmpty()) { 1053 KEduVocWordType *wordType = m_compability.typeFromOldFormat(m_doc->wordTypeContainer(), type); 1054 entry->translation(i)->setWordType(wordType); 1055 } 1056 1057 if (!remark.isEmpty()) 1058 entry->translation(i)->setComment(remark); 1059 if (!pronunciation.isEmpty()) 1060 entry->translation(i)->setPronunciation(pronunciation); 1061 1062 ///@todo include false friends from kvtml-1 again? 1063 // if ( !faux_ami_f.isEmpty() ) 1064 // entry->translation( i )->setFalseFriend( 0, faux_ami_f ); 1065 // if ( !faux_ami_t.isEmpty() ) 1066 // entry->translation( 0 )->setFalseFriend( i, faux_ami_t ); 1067 ///@todo include synonyms from kvtml-1 again? 1068 // if ( !synonym.isEmpty() ) 1069 // entry->translation( i )->setSynonym( synonym ); 1070 // if ( !antonym.isEmpty() ) 1071 // entry->translation( i )->setAntonym( antonym ); 1072 1073 if (!example.isEmpty()) 1074 entry->translation(i)->setExample(example); 1075 if (!paraphrase.isEmpty()) 1076 entry->translation(i)->setParaphrase(paraphrase); 1077 1078 if (i != 0) { 1079 entry->translation(i)->setGrade(grade); 1080 entry->translation(0)->setGrade(r_grade); 1081 entry->translation(i)->setPracticeCount(qcount); 1082 entry->translation(0)->setPracticeCount(r_qcount); 1083 entry->translation(i)->setBadCount(bcount); 1084 entry->translation(0)->setBadCount(r_bcount); 1085 entry->translation(i)->setPracticeDate(qdate); 1086 entry->translation(0)->setPracticeDate(r_qdate); 1087 } 1088 1089 // Next translation 1090 currentElement = currentElement.nextSiblingElement(KV_TRANS); 1091 i++; 1092 } 1093 1094 return true; 1095 } 1096 1097 bool KEduVocKvtmlReader::addLanguage(int languageId, const QString &locale) 1098 { 1099 if (m_doc->identifierCount() <= languageId) { 1100 m_doc->appendIdentifier(); 1101 // first entry 1102 if (!locale.isEmpty()) { // no definition in first entry 1103 m_doc->identifier(languageId).setLocale(locale); 1104 1105 QString languageName; 1106 // when using from qt-only apps this would crash (converter) 1107 languageName = QLocale::languageToString(QLocale(locale).language()); 1108 if (languageName.isEmpty()) { 1109 languageName = locale; 1110 } 1111 1112 m_doc->identifier(languageId).setName(languageName); 1113 qDebug() << "addLanguage( " << languageId << ", " << locale << "): " << languageName; 1114 } 1115 } else { 1116 if (!locale.isEmpty()) { 1117 if (locale != m_doc->identifier(languageId).locale()) { 1118 // different originals ? 1119 m_errorMessage = i18n("Ambiguous definition of language code"); 1120 return false; 1121 } 1122 } 1123 } 1124 return true; 1125 } 1126 1127 #include "moc_keduvockvtmlreader.cpp"