LibKEduVocDocument

keduvockvtmlreader.cpp
1/*
2 * read a KEduVocDocument from a KVTML file
3 * SPDX-FileCopyrightText: 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
4 * SPDX-FileCopyrightText: 2005 Eric Pignet <eric at erixpage.com>
5 * SPDX-FileCopyrightText: 2007 Peter Hedlund <peter.hedlund@kdemail.net>
6 * SPDX-FileCopyrightText: 2007 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10#include "keduvockvtmlreader.h"
11
12#include <KLocalizedString>
13#include <QIODevice>
14#include <QTextStream>
15
16#include <QDebug>
17#include <QLocale>
18
19#include "keduvoccommon_p.h"
20#include "keduvoclesson.h"
21#include "keduvocwordtype.h"
22#include "kvtmldefs.h"
23
25 : m_inputFile(&file)
26{
27 m_errorMessage = QLatin1String("");
28 qDebug() << "KEduVocKvtmlReader for kvtml version 1 files started.";
29}
30
32{
33 QTextStream ts(m_inputFile);
34 QString line1(ts.readLine());
35 QString line2(ts.readLine());
36
37 m_inputFile->seek(0);
38 return ((line1.startsWith(QLatin1String("<?xml"))) && (line2.indexOf(KV_DOCTYPE, 0) > 0));
39}
40
42{
43 m_doc = &doc;
44 m_cols = 0;
45 m_lines = 0;
46
47 QDomDocument domDoc(QStringLiteral("KEduVocDocument"));
48
49 const QDomDocument::ParseResult parseResult = domDoc.setContent(m_inputFile);
50 if (!parseResult) {
51 qDebug() << "Unable to load document.Parse error in line " << parseResult.errorLine << ", col " << parseResult.errorColumn << ": "
52 << qPrintable(parseResult.errorMessage);
54 }
55
56 QDomElement domElementKvtml = domDoc.documentElement();
57 if (domElementKvtml.tagName() != KV_DOCTYPE) {
58 m_errorMessage = i18n("This is not a KDE Vocabulary document.");
60 }
61
62 //-------------------------------------------------------------------------
63 // Attributes
64 //-------------------------------------------------------------------------
65
66 QDomAttr documentAttribute;
67 documentAttribute = domElementKvtml.attributeNode(KV_ENCODING);
68 if (!documentAttribute.isNull()) {
69 // TODO handle old encodings
70 // Qt DOM API autodetects encoding, so is there anything to do ?
71 }
72
73 documentAttribute = domElementKvtml.attributeNode(KV_TITLE);
74 if (!documentAttribute.isNull())
75 m_doc->setTitle(documentAttribute.value());
76
77 documentAttribute = domElementKvtml.attributeNode(KV_AUTHOR);
78 if (!documentAttribute.isNull())
79 m_doc->setAuthor(documentAttribute.value());
80
81 documentAttribute = domElementKvtml.attributeNode(KV_LICENSE);
82 if (!documentAttribute.isNull())
83 m_doc->setLicense(documentAttribute.value());
84
85 documentAttribute = domElementKvtml.attributeNode(KV_DOC_REM);
86 if (!documentAttribute.isNull())
87 m_doc->setDocumentComment(documentAttribute.value());
88
89 documentAttribute = domElementKvtml.attributeNode(KV_GENERATOR);
90 if (!documentAttribute.isNull()) {
91 m_doc->setGenerator(documentAttribute.value());
92 int pos = m_doc->generator().lastIndexOf(KVD_VERS_PREFIX);
93 if (pos >= 0)
94 m_doc->setVersion(m_doc->generator().remove(0, pos + 2));
95 }
96
97 documentAttribute = domElementKvtml.attributeNode(KV_COLS);
98 if (!documentAttribute.isNull())
99 m_cols = documentAttribute.value().toInt(); /// currently not used anywhere
100
101 documentAttribute = domElementKvtml.attributeNode(KV_LINES);
102 if (!documentAttribute.isNull())
103 m_lines = documentAttribute.value().toInt();
104
105 //-------------------------------------------------------------------------
106 // Children
107 //-------------------------------------------------------------------------
108
109 bool result = readBody(domElementKvtml); // read vocabulary
110
112}
113
114bool KEduVocKvtmlReader::readBody(QDomElement &domElementParent)
115{
116 bool result = false;
117
118 QDomElement currentElement;
119
120 currentElement = domElementParent.firstChildElement(KV_LESS_GRP);
121 if (!currentElement.isNull()) {
122 result = readLesson(currentElement);
123 if (!result)
124 return false;
125 }
126
127 currentElement = domElementParent.firstChildElement(KV_ARTICLE_GRP);
128 if (!currentElement.isNull()) {
129 result = readArticle(currentElement);
130 if (!result)
131 return false;
132 }
133
134 currentElement = domElementParent.firstChildElement(KV_CONJUG_GRP);
135 if (!currentElement.isNull()) {
136 int count = 0;
137
138 QDomElement domElementConjugChild = currentElement.firstChildElement(KV_CON_ENTRY);
139 while (!domElementConjugChild.isNull()) {
140 QString lang;
141 QDomAttr domAttrLang = domElementConjugChild.attributeNode(KV_LANG); // "l"
142 // make sure, the identifier is there
143 if (!addLanguage(count, domAttrLang.value())) {
144 return false;
145 }
146
147 KEduVocPersonalPronoun pronouns;
148 if (!readPersonalPronouns(domElementConjugChild, pronouns)) {
149 return false;
150 }
151 m_doc->identifier(count).setPersonalPronouns(pronouns);
152
153 count++;
154
155 domElementConjugChild = domElementConjugChild.nextSiblingElement(KV_CON_ENTRY);
156 }
157 }
158
159 // initialize the list of predefined types
160 m_compability.setupWordTypes(m_doc->wordTypeContainer());
161
162 currentElement = domElementParent.firstChildElement(KV_TYPE_GRP);
163 if (!currentElement.isNull()) {
164 result = readType(currentElement);
165 if (!result)
166 return false;
167 }
168
169 currentElement = domElementParent.firstChildElement(KV_TENSE_GRP);
170 if (!currentElement.isNull()) {
171 result = readTense(currentElement);
172 if (!result)
173 return false;
174 }
175
176 QDomNodeList entryList = domElementParent.elementsByTagName(KV_EXPR);
177 if (entryList.length() <= 0)
178 return false;
179
180 for (int i = 0; i < entryList.count(); ++i) {
181 currentElement = entryList.item(i).toElement();
182 if (currentElement.parentNode() == domElementParent) {
183 result = readExpression(currentElement);
184 if (!result)
185 return false;
186 }
187 }
188
189 for (int i = 0; i < m_doc->identifierCount(); i++) {
190 m_doc->identifier(i).setTenseList(m_compability.documentTenses());
191 }
192
193 return true;
194}
195
196bool KEduVocKvtmlReader::readLesson(QDomElement &domElementParent)
197{
198 QString s;
199 QDomAttr attribute;
200 QDomElement currentElement;
201
202 //-------------------------------------------------------------------------
203 // Children
204 //-------------------------------------------------------------------------
205
206 QDomNodeList entryList = domElementParent.elementsByTagName(KV_LESS_DESC);
207 if (entryList.length() <= 0)
208 return false;
209
210 for (int i = 0; i < entryList.count(); ++i) {
211 currentElement = entryList.item(i).toElement();
212 if (currentElement.parentNode() == domElementParent) {
213 int no = -1;
214
215 attribute = currentElement.attributeNode(KV_LESS_NO);
216 if (!attribute.isNull()) {
217 no = attribute.value().toInt();
218 }
219
220 bool inQuery = false;
221 attribute = currentElement.attributeNode(KV_LESS_QUERY);
222 if (!attribute.isNull()) {
223 inQuery = (attribute.value().toInt() != 0);
224 }
225
226 s = currentElement.text();
227 KEduVocLesson *lesson = new KEduVocLesson(s, m_doc->lesson());
228 lesson->setInPractice(inQuery);
229 m_doc->lesson()->appendChildContainer(lesson);
230 if (m_doc->lesson()->childContainerCount() != no - 1) {
231 qDebug() << "Warning! Lesson order may be confused. Are all lessons in order in the file?";
232 }
233 }
234 }
235
236 return true;
237}
238
239bool KEduVocKvtmlReader::readArticle(QDomElement &domElementParent)
240/*
241 <article>
242 <e l="de"> lang determines also lang order in entries !!
243 <fi>eine</fi> which must NOT differ
244 <fd>die</fd>
245 <mi>ein</mi>
246 <md>der</md>
247 <ni>ein</ni>
248 <nd>das</nd>
249 </e>
250 </article>
251*/
252{
253 QString s;
254 QDomAttr attribute;
255 QDomElement currentElement;
256 QDomElement article;
257
258 QDomNodeList entryList = domElementParent.elementsByTagName(KV_ART_ENTRY);
259 if (entryList.length() <= 0)
260 return false;
261
262 for (int i = 0; i < entryList.count(); ++i) {
263 // qDebug() << "KEduVocKvtmlReader::readArticle() read " << entryList.count() << " articles. ";
264 currentElement = entryList.item(i).toElement();
265 if (currentElement.parentNode() == domElementParent) {
266 QString lang;
267 attribute = currentElement.attributeNode(KV_LANG);
268
269 if (!addLanguage(i, attribute.value())) {
270 return false;
271 }
272
273 //---------
274 // Children
275
276 QString fem_def = QLatin1String("");
277 QString mal_def = QLatin1String("");
278 QString nat_def = QLatin1String("");
279 QString fem_indef = QLatin1String("");
280 QString mal_indef = QLatin1String("");
281 QString nat_indef = QLatin1String("");
282
283 article = currentElement.firstChildElement(KV_ART_FD);
284 if (!article.isNull()) {
285 fem_def = article.text();
286 if (fem_def.isNull())
287 fem_def = QLatin1String("");
288 }
289
290 article = currentElement.firstChildElement(KV_ART_FI);
291 if (!article.isNull()) {
292 fem_indef = article.text();
293 if (fem_indef.isNull())
294 fem_indef = QLatin1String("");
295 }
296
297 article = currentElement.firstChildElement(KV_ART_MD);
298 if (!article.isNull()) {
299 mal_def = article.text();
300 if (mal_def.isNull())
301 mal_def = QLatin1String("");
302 }
303
304 article = currentElement.firstChildElement(KV_ART_MI);
305 if (!article.isNull()) {
306 mal_indef = article.text();
307 if (mal_indef.isNull())
308 mal_indef = QLatin1String("");
309 }
310
311 article = currentElement.firstChildElement(KV_ART_ND);
312 if (!article.isNull()) {
313 nat_def = article.text();
314 if (nat_def.isNull())
315 nat_def = QLatin1String("");
316 }
317
318 article = currentElement.firstChildElement(KV_ART_NI);
319 if (!article.isNull()) {
320 nat_indef = article.text();
321 if (nat_indef.isNull())
322 nat_indef = QLatin1String("");
323 }
324
325 KEduVocArticle article;
326 article.setArticle(mal_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Masculine);
327 article.setArticle(fem_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Feminine);
328 article.setArticle(nat_def, KEduVocWordFlag::Singular | KEduVocWordFlag::Definite | KEduVocWordFlag::Neuter);
329 article.setArticle(mal_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Masculine);
330 article.setArticle(fem_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Feminine);
331 article.setArticle(nat_indef, KEduVocWordFlag::Singular | KEduVocWordFlag::Indefinite | KEduVocWordFlag::Neuter);
332 m_doc->identifier(i).setArticle(article);
333 }
334 }
335
336 return true;
337}
338
339bool KEduVocKvtmlReader::readTranslationConjugations(QDomElement &domElementParent, KEduVocTranslation *translation)
340{
341 QString tense;
342
343 QDomElement domElementConjugChild = domElementParent.firstChildElement(KV_CON_TYPE);
344 while (!domElementConjugChild.isNull()) {
345 // "n" == is the type is the tense
346 QDomAttr domAttrLang = domElementConjugChild.attributeNode(KV_CON_NAME);
347 QString oldShortTense = domAttrLang.value();
348
349 tense = m_compability.tenseFromKvtml1(oldShortTense);
350 KEduVocConjugation conjugation;
351 readConjugation(domElementConjugChild, conjugation);
352 translation->setConjugation(tense, conjugation);
353
354 domElementConjugChild = domElementConjugChild.nextSiblingElement(KV_CON_TYPE);
355 } // while -> next tense, count++
356 return true;
357}
358
359bool KEduVocKvtmlReader::readConjugation(QDomElement &domElementParent, KEduVocConjugation &conjugation)
360/*
361 <conjugation> used in header for definition of "prefix"
362 <e l="de"> lang determines also lang order in entries !!
363 <s1>I</s1> which must NOT differ
364 <s2>you<2>
365 <s3f>he</s3f>
366 <s3m>she</s3m>
367 <s3n>it</s3n>
368 <p1>we</p1>
369 <p2>you</p2>
370 <p3f>they</p3f>
371 <p3m>they</p3m>
372 <p3n>they</p3n>
373 </e>
374 </conjugation>
375
376 <conjugation> and in entry for definition of tenses of (irreg.) verbs
377 <t n="sipa">
378 <s1>go</s1>
379 <s2>go</s2>
380 <s3f>goes</s3f>
381 <s3m>goes</s3m>
382 <s3n>goes</s3n>
383 <p1>go</p1>
384 <p2>go</p2>
385 <p3f>go</p3f>
386 <p3m>go</p3m>
387 <p3n>go</p3n>
388 </t>
389 </conjugation>
390*/
391{
392 // QString s;
393 bool p3_common;
394 bool s3_common;
395 QString pers1_sing;
396 QString pers2_sing;
397 QString pers3_m_sing;
398 QString pers3_f_sing;
399 QString pers3_n_sing;
400 QString pers1_plur;
401 QString pers2_plur;
402 QString pers3_m_plur;
403 QString pers3_f_plur;
404 QString pers3_n_plur;
405
406 p3_common = false;
407 s3_common = false;
408
409 // get the individual entries for persons...
410 QDomElement domElementConjugGrandChild = domElementParent.firstChild().toElement();
411 while (!domElementConjugGrandChild.isNull()) {
412 if (domElementConjugGrandChild.tagName() == KV_CON_P1S) {
413 pers1_sing = domElementConjugGrandChild.text();
414 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2S) {
415 pers2_sing = domElementConjugGrandChild.text();
416 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SF) {
417 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON);
418 if (!domAttrCommon.isNull())
419 s3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails
420 pers3_f_sing = domElementConjugGrandChild.text();
421
422 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SM) {
423 pers3_m_sing = domElementConjugGrandChild.text();
424
425 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SN) {
426 pers3_n_sing = domElementConjugGrandChild.text();
427
428 } else if (domElementConjugGrandChild.tagName() == KV_CON_P1P) {
429 pers1_plur = domElementConjugGrandChild.text();
430
431 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2P) {
432 pers2_plur = domElementConjugGrandChild.text();
433
434 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PF) {
435 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON);
436 if (!domAttrCommon.isNull())
437 p3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails
438
439 pers3_f_plur = domElementConjugGrandChild.text();
440
441 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PM) {
442 pers3_m_plur = domElementConjugGrandChild.text();
443
444 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PN) {
445 pers3_n_plur = domElementConjugGrandChild.text();
446
447 } else {
448 return false;
449 }
450
451 domElementConjugGrandChild = domElementConjugGrandChild.nextSibling().toElement();
452 } // while - probably to be sure, because the persons could be in any order.
453 // I guess this goes over only one set, such as:
454 // <s1>traigo</s1><s2>traes</s2><s3fcommon="1">trae</s3f>
455 // <p1>traemos</p1><p2>traéis</p2><p3f common="1">traen</p3f>
456 // until no elements are left in that soup.
457
458 // now set the data: [count] - number of conjug?
459 // type - the tense?
460 // finally the person
461
462 const KEduVocWordFlags numS = KEduVocWordFlag::Singular;
463 const KEduVocWordFlags numP = KEduVocWordFlag::Plural;
464
465 conjugation.setConjugation(pers1_sing, KEduVocWordFlag::First | numS);
466 conjugation.setConjugation(pers2_sing, KEduVocWordFlag::Second | numS);
467 conjugation.setConjugation(pers1_plur, KEduVocWordFlag::First | numP);
468 conjugation.setConjugation(pers2_plur, KEduVocWordFlag::Second | numP);
469
470 if (s3_common) {
471 conjugation.setConjugation(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Singular);
472 } else {
473 conjugation.setConjugation(pers3_m_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | KEduVocWordFlag::Singular);
474 conjugation.setConjugation(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | KEduVocWordFlag::Singular);
475 conjugation.setConjugation(pers3_n_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Singular);
476 }
477
478 if (p3_common) {
479 conjugation.setConjugation(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Plural);
480 } else {
481 conjugation.setConjugation(pers3_m_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | KEduVocWordFlag::Plural);
482 conjugation.setConjugation(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | KEduVocWordFlag::Plural);
483 conjugation.setConjugation(pers3_n_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | KEduVocWordFlag::Plural);
484 }
485
486 return true;
487}
488
489bool KEduVocKvtmlReader::readPersonalPronouns(QDomElement &domElementParent, KEduVocPersonalPronoun &pronouns)
490{
491 // QString s;
492 bool p3_common;
493 bool s3_common;
494 QString pers1_sing;
495 QString pers2_sing;
496 QString pers3_m_sing;
497 QString pers3_f_sing;
498 QString pers3_n_sing;
499 QString pers1_plur;
500 QString pers2_plur;
501 QString pers3_m_plur;
502 QString pers3_f_plur;
503 QString pers3_n_plur;
504
505 p3_common = false;
506 s3_common = false;
507
508 // get the individual entries for persons...
509 QDomElement domElementConjugGrandChild = domElementParent.firstChild().toElement();
510 while (!domElementConjugGrandChild.isNull()) {
511 if (domElementConjugGrandChild.tagName() == KV_CON_P1S) {
512 pers1_sing = domElementConjugGrandChild.text();
513 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2S) {
514 pers2_sing = domElementConjugGrandChild.text();
515 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SF) {
516 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON);
517 if (!domAttrCommon.isNull())
518 s3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails
519 pers3_f_sing = domElementConjugGrandChild.text();
520
521 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SM) {
522 pers3_m_sing = domElementConjugGrandChild.text();
523
524 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3SN) {
525 pers3_n_sing = domElementConjugGrandChild.text();
526
527 } else if (domElementConjugGrandChild.tagName() == KV_CON_P1P) {
528 pers1_plur = domElementConjugGrandChild.text();
529
530 } else if (domElementConjugGrandChild.tagName() == KV_CON_P2P) {
531 pers2_plur = domElementConjugGrandChild.text();
532
533 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PF) {
534 QDomAttr domAttrCommon = domElementConjugGrandChild.attributeNode(KV_CONJ_COMMON);
535 if (!domAttrCommon.isNull())
536 p3_common = domAttrCommon.value().toInt(); // returns 0 if the conversion fails
537
538 pers3_f_plur = domElementConjugGrandChild.text();
539
540 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PM) {
541 pers3_m_plur = domElementConjugGrandChild.text();
542
543 } else if (domElementConjugGrandChild.tagName() == KV_CON_P3PN) {
544 pers3_n_plur = domElementConjugGrandChild.text();
545
546 } else {
547 return false;
548 }
549
550 domElementConjugGrandChild = domElementConjugGrandChild.nextSibling().toElement();
551 } // while - probably to be sure, because the persons could be in any order.
552 // I guess this goes over only one set, such as:
553 // <s1>traigo</s1><s2>traes</s2><s3fcommon="1">trae</s3f>
554 // <p1>traemos</p1><p2>traéis</p2><p3f common="1">traen</p3f>
555 // until no elements are left in that soup.
556
557 // now set the data: [count] - number of conjug?
558 // type - the tense?
559 // finally the person
560
561 KEduVocWordFlags numS = KEduVocWordFlag::Singular;
562 pronouns.setMaleFemaleDifferent(false);
563 pronouns.setPersonalPronoun(pers1_sing, KEduVocWordFlag::First | numS);
564 pronouns.setPersonalPronoun(pers2_sing, KEduVocWordFlag::Second | numS);
565
566 // used to have common in female
567 if (s3_common) {
568 pronouns.setPersonalPronoun(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numS);
569 } else {
570 pronouns.setPersonalPronoun(pers3_m_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | numS);
571 pronouns.setPersonalPronoun(pers3_f_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | numS);
572 pronouns.setPersonalPronoun(pers3_n_sing, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numS);
573 pronouns.setMaleFemaleDifferent(true);
574 }
575
576 KEduVocWordFlags numP = KEduVocWordFlag::Plural;
577
578 pronouns.setPersonalPronoun(pers1_plur, KEduVocWordFlag::First | numP);
579 pronouns.setPersonalPronoun(pers2_plur, KEduVocWordFlag::Second | numP);
580 if (p3_common) {
581 pronouns.setPersonalPronoun(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numP);
582 } else {
583 pronouns.setPersonalPronoun(pers3_m_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Masculine | numP);
584 pronouns.setPersonalPronoun(pers3_f_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Feminine | numP);
585 pronouns.setPersonalPronoun(pers3_n_plur, KEduVocWordFlag::Third | KEduVocWordFlag::Neuter | numP);
586 pronouns.setMaleFemaleDifferent(true);
587 }
588
589 return true;
590}
591
592bool KEduVocKvtmlReader::readType(QDomElement &domElementParent)
593{
594 QString s;
595 QDomElement currentElement;
596
597 QDomNodeList entryList = domElementParent.elementsByTagName(KV_TYPE_DESC);
598 if (entryList.length() <= 0)
599 return false;
600
601 for (int i = 0; i < entryList.count(); ++i) {
602 currentElement = entryList.item(i).toElement();
603 if (currentElement.parentNode() == domElementParent) {
604 // We need to even add empty elements since the old system relied on
605 // the order. So "type1" "" "type2" should be just like that.
606
607 qDebug() << "Adding old self defined type: " << currentElement.text();
608 // add the type to the list of available types
609 KEduVocWordType *type = new KEduVocWordType(currentElement.text(), m_doc->wordTypeContainer());
610 m_doc->wordTypeContainer()->appendChildContainer(type);
611
612 // from this the #1 are transformed to something sensible again
613 m_oldSelfDefinedTypes.append(currentElement.text());
614 }
615 }
616
617 return true;
618}
619
620bool KEduVocKvtmlReader::readTense(QDomElement &domElementParent)
621{
622 QDomElement currentElement;
623
624 currentElement = domElementParent.firstChildElement(KV_TENSE_DESC);
625 while (!currentElement.isNull()) {
626 qDebug() << "Reading user defined tense description: " << currentElement.text();
627 m_compability.addUserdefinedTense(currentElement.text());
628 currentElement = currentElement.nextSiblingElement(KV_TENSE_DESC);
629 }
630 return true;
631}
632
633bool KEduVocKvtmlReader::readComparison(QDomElement &domElementParent, KEduVocTranslation *translation)
634/*
635 <comparison>
636 <l1>good</l1> --- this one is dead as it always has to be the word itself
637 <l2>better</l2>
638 <l3>best</l3>
639 </comparison>
640*/
641{
642 QDomElement currentElement;
643
644 currentElement = domElementParent.firstChildElement(KV_COMP_L2);
645 translation->setComparativeForm(currentElement.text());
646
647 currentElement = domElementParent.firstChildElement(KV_COMP_L3);
648 translation->setSuperlativeForm(currentElement.text());
649
650 return true;
651}
652
653bool KEduVocKvtmlReader::readMultipleChoice(QDomElement &domElementParent, KEduVocTranslation *translation)
654/*
655 <multiplechoice>
656 <mc1>good</mc1>
657 <mc2>better</mc2>
658 <mc3>best</mc3>
659 <mc4>best 2</mc4>
660 <mc5>best 3</mc5>
661 </multiplechoice>
662*/
663
664{
665 QDomElement currentElement;
666 QStringList choices = translation->getMultipleChoice();
667
668 currentElement = domElementParent.firstChildElement(KV_MC_1);
669 if (!currentElement.isNull()) {
670 choices.append(currentElement.text());
671 }
672
673 currentElement = domElementParent.firstChildElement(KV_MC_2);
674 if (!currentElement.isNull()) {
675 choices.append(currentElement.text());
676 }
677
678 currentElement = domElementParent.firstChildElement(KV_MC_3);
679 if (!currentElement.isNull()) {
680 choices.append(currentElement.text());
681 }
682
683 currentElement = domElementParent.firstChildElement(KV_MC_4);
684 if (!currentElement.isNull()) {
685 choices.append(currentElement.text());
686 }
687
688 currentElement = domElementParent.firstChildElement(KV_MC_5);
689 if (!currentElement.isNull()) {
690 choices.append(currentElement.text());
691 }
692
693 translation->setMultipleChoice(choices);
694
695 return true;
696}
697
698bool KEduVocKvtmlReader::readExpressionChildAttributes(QDomElement &domElementExpressionChild,
699 QString &lang,
700 grade_t &grade,
701 grade_t &rev_grade,
702 int &count,
703 int &rev_count,
704 QDateTime &date,
705 QDateTime &rev_date,
706 QString &remark,
707 int &bcount,
708 int &rev_bcount,
709 QString &query_id,
710 QString &pronunciation,
711 int &width,
712 QString &type,
713 QString &faux_ami_f,
714 QString &faux_ami_t,
715 QString &synonym,
716 QString &example,
717 QString &antonym,
718 QSet<QString> &usages,
719 QString &paraphrase)
720{
721 Q_UNUSED(usages)
722 int pos;
723 QDomAttr attribute;
724
725 lang = QLatin1String("");
726 attribute = domElementExpressionChild.attributeNode(KV_LANG);
727 if (!attribute.isNull())
728 lang = attribute.value();
729
730 width = -1;
731 attribute = domElementExpressionChild.attributeNode(KV_SIZEHINT);
732 if (!attribute.isNull())
733 width = attribute.value().toInt();
734
735 grade = KV_NORM_GRADE;
736 rev_grade = KV_NORM_GRADE;
737 attribute = domElementExpressionChild.attributeNode(KV_GRADE);
738 if (!attribute.isNull()) {
739 QString s = attribute.value();
740 if ((pos = s.indexOf(';')) >= 1) {
741 grade = QStringView(s).left(pos).toInt();
742 rev_grade = QStringView(s).mid(pos + 1, s.length()).toInt();
743 } else
744 grade = s.toInt();
745 }
746
747 count = 0;
748 rev_count = 0;
749 attribute = domElementExpressionChild.attributeNode(KV_COUNT);
750 if (!attribute.isNull()) {
751 QString s = attribute.value();
752 if ((pos = s.indexOf(';')) >= 1) {
753 count = QStringView(s).left(pos).toInt();
754 rev_count = QStringView(s).mid(pos + 1, s.length()).toInt();
755 } else
756 count = s.toInt();
757 }
758
759 bcount = 0;
760 rev_bcount = 0;
761 attribute = domElementExpressionChild.attributeNode(KV_BAD);
762 if (!attribute.isNull()) {
763 QString s = attribute.value();
764 if ((pos = s.indexOf(';')) >= 1) {
765 bcount = QStringView(s).left(pos).toInt();
766 rev_bcount = QStringView(s).mid(pos + 1, s.length()).toInt();
767 } else
768 bcount = s.toInt();
769 }
770
772 rev_date = QDateTime::fromSecsSinceEpoch(0);
773 attribute = domElementExpressionChild.attributeNode(KV_DATE);
774 if (!attribute.isNull()) {
775 QString s = attribute.value();
776 if ((pos = s.indexOf(';')) >= 1) {
777 date = QDateTime::fromSecsSinceEpoch(QStringView(s).left(pos).toInt());
778 rev_date = QDateTime::fromSecsSinceEpoch(QStringView(s).mid(pos + 1, s.length()).toInt());
779 } else
781 }
782
783 attribute = domElementExpressionChild.attributeNode(KV_DATE2);
784 if (!attribute.isNull()) {
785 // this format is deprecated and ignored.
786 }
787
788 remark = QLatin1String("");
789 attribute = domElementExpressionChild.attributeNode(KV_REMARK);
790 if (!attribute.isNull())
791 remark = attribute.value();
792
793 faux_ami_f = QLatin1String("");
794 attribute = domElementExpressionChild.attributeNode(KV_FAUX_AMI_F);
795 if (!attribute.isNull())
796 faux_ami_f = attribute.value();
797
798 faux_ami_t = QLatin1String("");
799 attribute = domElementExpressionChild.attributeNode(KV_FAUX_AMI_T);
800 if (!attribute.isNull())
801 faux_ami_t = attribute.value();
802
803 synonym = QLatin1String("");
804 attribute = domElementExpressionChild.attributeNode(KV_SYNONYM);
805 if (!attribute.isNull())
806 synonym = attribute.value();
807
808 example = QLatin1String("");
809 attribute = domElementExpressionChild.attributeNode(KV_EXAMPLE);
810 if (!attribute.isNull())
811 example = attribute.value();
812
813 paraphrase = QLatin1String("");
814 attribute = domElementExpressionChild.attributeNode(KV_PARAPHRASE);
815 if (!attribute.isNull())
816 paraphrase = attribute.value();
817
818 antonym = QLatin1String("");
819 attribute = domElementExpressionChild.attributeNode(KV_ANTONYM);
820 if (!attribute.isNull())
821 antonym = attribute.value();
822
823 // this is all done by reference - so we have to care about "type" :(
824 attribute = domElementExpressionChild.attributeNode(KV_EXPRTYPE);
825 if (!attribute.isNull()) {
826 type = attribute.value();
827 }
828
829 pronunciation = QLatin1String("");
830 attribute = domElementExpressionChild.attributeNode(KV_PRONUNCE);
831 if (!attribute.isNull())
832 pronunciation = attribute.value();
833
834 query_id = QLatin1String("");
835 attribute = domElementExpressionChild.attributeNode(KV_QUERY);
836 if (!attribute.isNull())
837 query_id = attribute.value();
838
839 return true;
840}
841
843{
844 grade_t grade;
845 grade_t r_grade;
846 int qcount;
847 int r_qcount;
848 int bcount;
849 int r_bcount;
850 QString remark;
851 QString pronunciation;
852 QDateTime qdate;
853 QDateTime r_qdate;
854 // bool inquery;
855 bool active;
856 QString lang;
857 QString textstr;
858 QString q_org;
859 QString q_trans;
860 QString query_id;
861 int width;
862 QString type;
863 QString faux_ami_f;
864 QString faux_ami_t;
865 QString synonym;
866 QString example;
867 QString antonym;
868 QSet<QString> usage;
869 QString paraphrase;
870
871 QDomAttr attribute;
872 QDomElement currentElement;
873 QDomElement currentChild;
874
875 int lessonNumber = -1;
876
877 //-------------------------------------------------------------------------
878 // Attributes
879 //-------------------------------------------------------------------------
880
881 attribute = domElementParent.attributeNode(KV_LESS_MEMBER);
882 if (!attribute.isNull()) {
883 // we start counting from 0 in new documents
884 lessonNumber = attribute.value().toInt() - 1;
885 if (lessonNumber > m_doc->lesson()->childContainerCount()) {
886 ///@todo can this happen? does it need a while loop?
887 // it's from a lesson that hasn't been added yet
888 // so make sure this lesson is in the document
889 qDebug() << "Warning: lesson > m_doc->lessonCount() in readExpression.";
890
891 KEduVocLesson *lesson = new KEduVocLesson(i18nc("A generic name for a new lesson and its number.", "Lesson %1", lessonNumber), m_doc->lesson());
892 m_doc->lesson()->appendChildContainer(lesson);
893 }
894 }
895
896 attribute = domElementParent.attributeNode(KV_SELECTED);
897 // if ( !attribute.isNull() )
898 // inquery = attribute.value() == "1" ? true : false;
899 // else
900 // inquery = false;
901
902 attribute = domElementParent.attributeNode(KV_INACTIVE);
903 if (!attribute.isNull())
904 active = attribute.value() == QLatin1Char('1') ? false : true;
905 else
906 active = true;
907
908 // this is all done by reference - so we have to care about "type" :(
909 attribute = domElementParent.attributeNode(KV_EXPRTYPE);
910 if (!attribute.isNull()) {
911 type = attribute.value();
912 }
913
914 //-------------------------------------------------------------------------
915 // Children 'Translation'
916 //-------------------------------------------------------------------------
917
918 // QDomNodeList translationList = domElementParent.elementsByTagName(KV_TRANS);
919
920 // count which translation we are on
921 int i = 0;
922
923 // kvtml 1: we always have an original element (required)
924 currentElement = domElementParent.firstChildElement(KV_ORG);
925 if (currentElement.isNull()) { // sanity check
926 m_errorMessage = i18n("Data for original language missing");
927 return false;
928 }
929
930 KEduVocExpression *entry = nullptr;
931
932 while (!currentElement.isNull()) {
933 //-----------
934 // Attributes
935 //-----------
936
937 // read attributes - the order of the query grades is interchanged!
938 if (i == 0
939 && !readExpressionChildAttributes(currentElement,
940 lang,
941 grade,
942 r_grade,
943 qcount,
944 r_qcount,
945 qdate,
946 r_qdate,
947 remark,
948 bcount,
949 r_bcount,
950 query_id,
951 pronunciation,
952 width,
953 type,
954 faux_ami_t,
955 faux_ami_f,
956 synonym,
957 example,
958 antonym,
959 usage,
960 paraphrase)) {
961 return false;
962 }
963
964 if (i != 0
965 && !readExpressionChildAttributes(currentElement,
966 lang,
967 grade,
968 r_grade,
969 qcount,
970 r_qcount,
971 qdate,
972 r_qdate,
973 remark,
974 bcount,
975 r_bcount,
976 query_id,
977 pronunciation,
978 width,
979 type,
980 faux_ami_f,
981 faux_ami_t,
982 synonym,
983 example,
984 antonym,
985 usage,
986 paraphrase)) {
987 return false;
988 }
989
990 //---------
991 // Children
992
993 textstr = currentElement.lastChild().toText().data();
994
995 if (i == 0) {
996 entry = new KEduVocExpression(textstr);
997 entry->setActive(active);
998 if (lessonNumber != -1) {
999 static_cast<KEduVocLesson *>(m_doc->lesson()->childContainer(lessonNumber))->appendEntry(entry);
1000 } else {
1001 m_doc->lesson()->appendEntry(entry);
1002 }
1003 } else {
1004 entry->setTranslation(i, textstr);
1005 }
1006
1007 if (m_doc->lesson()->entries(KEduVocLesson::Recursive).count() == 1) { // this is because in kvtml the languages are saved in the FIRST ENTRY ONLY.
1008 // new translation
1009 if (!addLanguage(i, lang)) {
1010 return false;
1011 }
1012 }
1013
1014 // better make sure, translation(i) already exists...
1015 currentChild = currentElement.firstChildElement(KV_CONJUG_GRP);
1016 if (!currentChild.isNull()) {
1017 if (!readTranslationConjugations(currentChild, entry->translation(i))) {
1018 return false;
1019 }
1020 }
1021
1022 currentChild = currentElement.firstChildElement(KV_MULTIPLECHOICE_GRP);
1023 if (!currentChild.isNull()) {
1024 if (!readMultipleChoice(currentChild, entry->translation(i))) {
1025 return false;
1026 }
1027 }
1028
1029 currentChild = currentElement.firstChildElement(KV_COMPARISON_GRP);
1030 if (!currentChild.isNull()) {
1031 if (!readComparison(currentChild, entry->translation(i))) {
1032 return false;
1033 }
1034 }
1035
1036 if (!type.isEmpty()) {
1037 KEduVocWordType *wordType = m_compability.typeFromOldFormat(m_doc->wordTypeContainer(), type);
1038 entry->translation(i)->setWordType(wordType);
1039 }
1040
1041 if (!remark.isEmpty())
1042 entry->translation(i)->setComment(remark);
1043 if (!pronunciation.isEmpty())
1044 entry->translation(i)->setPronunciation(pronunciation);
1045
1046 ///@todo include false friends from kvtml-1 again?
1047 // if ( !faux_ami_f.isEmpty() )
1048 // entry->translation( i )->setFalseFriend( 0, faux_ami_f );
1049 // if ( !faux_ami_t.isEmpty() )
1050 // entry->translation( 0 )->setFalseFriend( i, faux_ami_t );
1051 ///@todo include synonyms from kvtml-1 again?
1052 // if ( !synonym.isEmpty() )
1053 // entry->translation( i )->setSynonym( synonym );
1054 // if ( !antonym.isEmpty() )
1055 // entry->translation( i )->setAntonym( antonym );
1056
1057 if (!example.isEmpty())
1058 entry->translation(i)->setExample(example);
1059 if (!paraphrase.isEmpty())
1060 entry->translation(i)->setParaphrase(paraphrase);
1061
1062 if (i != 0) {
1063 entry->translation(i)->setGrade(grade);
1064 entry->translation(0)->setGrade(r_grade);
1065 entry->translation(i)->setPracticeCount(qcount);
1066 entry->translation(0)->setPracticeCount(r_qcount);
1067 entry->translation(i)->setBadCount(bcount);
1068 entry->translation(0)->setBadCount(r_bcount);
1069 entry->translation(i)->setPracticeDate(qdate);
1070 entry->translation(0)->setPracticeDate(r_qdate);
1071 }
1072
1073 // Next translation
1074 currentElement = currentElement.nextSiblingElement(KV_TRANS);
1075 i++;
1076 }
1077
1078 return true;
1079}
1080
1081bool KEduVocKvtmlReader::addLanguage(int languageId, const QString &locale)
1082{
1083 if (m_doc->identifierCount() <= languageId) {
1084 m_doc->appendIdentifier();
1085 // first entry
1086 if (!locale.isEmpty()) { // no definition in first entry
1087 m_doc->identifier(languageId).setLocale(locale);
1088
1089 QString languageName;
1090 // when using from qt-only apps this would crash (converter)
1091 languageName = QLocale::languageToString(QLocale(locale).language());
1092 if (languageName.isEmpty()) {
1093 languageName = locale;
1094 }
1095
1096 m_doc->identifier(languageId).setName(languageName);
1097 qDebug() << "addLanguage( " << languageId << ", " << locale << "): " << languageName;
1098 }
1099 } else {
1100 if (!locale.isEmpty()) {
1101 if (locale != m_doc->identifier(languageId).locale()) {
1102 // different originals ?
1103 m_errorMessage = i18n("Ambiguous definition of language code");
1104 return false;
1105 }
1106 }
1107 }
1108 return true;
1109}
1110
1111#include "moc_keduvockvtmlreader.cpp"
The conjugation of a verb.
void setConjugation(const KEduVocText &conjugation, KEduVocWordFlags flags)
Updates or creates the conjugation object for the given word flags.
The primary entry point to the hierarchy of objects describing vocabularies.
ErrorCode
the return code when opening/saving
@ InvalidXml
malformed xml or bad file formatting
@ FileTypeUnknown
unknown file type
@ FileReaderFailed
file reader failed
This class contains one vocabulary expression as an original with one or more translations.
void setTranslation(int index, const QString &expression)
Add a translation to this expression.
void setActive(bool flag=true)
set entry active (enabled for queries)
KEduVocTranslation * translation(int index)
Get a pointer to the translation.
virtual bool isParsable()
Can this reader parse this file.
bool readExpression(QDomElement &domElementParent)
KEduVocKvtmlReader(QIODevice &file)
constructor
virtual KEduVocDocument::ErrorCode read(KEduVocDocument &doc)
Parse file and write into doc.
bool addLanguage(int languageId, const QString &language)
Attempt to add a language/locale.
class to store information about a lesson
void appendEntry(KEduVocExpression *entry)
append an entry to the lesson
The conjugation of a verb.
void setPracticeCount(count_t count)
set how often this entry has been practiced as int
void setBadCount(count_t count)
set bad query count as int
void setPracticeDate(const QDateTime &date)
Set last query date.
void setGrade(grade_t grade)
sets the grade
void setExample(const QString &expression)
Sets example this expression.
QStringList getMultipleChoice() const
Returns multiple choice if available.
void setConjugation(const QString &tense, const KEduVocConjugation &conjugation)
adds conjugations or replaces them, if they exist.
void setMultipleChoice(const QStringList &choices)
Sets multiple choice.
void setParaphrase(const QString &expression)
Sets paraphrase of this expression.
void setWordType(KEduVocWordType *wordType)
Sets the word type of this expression.
void setPronunciation(const QString &expression)
Sets the pronunciation of this expression.
void setComment(const QString &expr)
Sets comment of this expression.
class to store translation word types
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
QDateTime fromSecsSinceEpoch(qint64 secs)
QString value() const const
QString data() const const
QDomElement documentElement() const const
ParseResult setContent(QAnyStringView text, ParseOptions options)
QDomAttr attributeNode(const QString &name)
QDomNodeList elementsByTagName(const QString &tagname) const const
QString tagName() const const
QString text() const const
QDomNode firstChild() const const
QDomElement firstChildElement(const QString &tagName, const QString &namespaceURI) const const
bool isNull() const const
QDomNode lastChild() const const
QDomNode nextSibling() const const
QDomElement nextSiblingElement(const QString &tagName, const QString &namespaceURI) const const
QDomNode parentNode() const const
QDomElement toElement() const const
QDomText toText() const const
int count() const const
QDomNode item(int index) const const
int length() const const
void append(QList< T > &&value)
QString languageToString(Language language)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QTextStream & left(QTextStream &stream)
QString readLine(qint64 maxlen)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 31 2025 12:09:38 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.