File indexing completed on 2022-10-04 13:56:35

0001 /*
0002  * export a KEduVocDocument to a KVTML file
0003  * SPDX-FileCopyrightText: 2007 Jeremy Whiting <jpwhiting@kde.org>
0004  * SPDX-FileCopyrightText: 2007-2010 Frederik Gladhorn <gladhorn@kde.org>
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 #include "keduvockvtml2writer.h"
0008 
0009 #include <QTextStream>
0010 
0011 #include <QDir>
0012 #include <QDebug>
0013 
0014 #include "keduvocdocument.h"
0015 #include "keduvocexpression.h"
0016 #include "keduvoclesson.h"
0017 #include "keduvocleitnerbox.h"
0018 #include "keduvocwordtype.h"
0019 #include "kvtml2defs.h"
0020 #include <kio/global.h>
0021 
0022 KEduVocKvtml2Writer::KEduVocKvtml2Writer( QFile *file )
0023 {
0024     // the file must be already open
0025     m_outputFile = file;
0026 }
0027 
0028 bool KEduVocKvtml2Writer::writeDoc( KEduVocDocument *doc, const QString &generator )
0029 {
0030     if (createXmlDocument(doc, generator)) {
0031         QTextStream ts( m_outputFile );
0032         m_domDoc.save( ts, 2 );
0033         return true;
0034     }
0035     return false;
0036 }
0037 
0038 QByteArray KEduVocKvtml2Writer::toByteArray(KEduVocDocument * doc, const QString & generator)
0039 {
0040     if (createXmlDocument(doc, generator)) {
0041         return m_domDoc.toByteArray();
0042     }
0043     return QByteArray();
0044 }
0045 
0046 bool KEduVocKvtml2Writer::createXmlDocument( KEduVocDocument *doc, const QString &generator )
0047 {
0048     m_doc = doc;
0049 
0050     m_domDoc = QDomDocument( QStringLiteral("kvtml PUBLIC \"kvtml2.dtd\" \"http://edu.kde.org/kvtml/kvtml2.dtd\"") );
0051     m_domDoc.appendChild( m_domDoc.createProcessingInstruction( QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"") ) );
0052     QDomElement domElementKvtml = m_domDoc.createElement( QStringLiteral("kvtml") );
0053     m_domDoc.appendChild( domElementKvtml );
0054 
0055     domElementKvtml.setAttribute( KVTML_VERSION, ( QString ) QStringLiteral("2.0") );
0056 
0057     // information group
0058     QDomElement currentElement = m_domDoc.createElement( KVTML_INFORMATION );
0059     writeInformation( currentElement, generator );
0060     domElementKvtml.appendChild( currentElement );
0061 
0062     // identifiers
0063     currentElement = m_domDoc.createElement( KVTML_IDENTIFIERS );
0064     writeIdentifiers( currentElement );
0065     domElementKvtml.appendChild( currentElement );
0066 
0067     // entries
0068     currentElement = m_domDoc.createElement( KVTML_ENTRIES );
0069     if ( !writeEntries( currentElement ) ) {
0070         // at least one entry is required!
0071         return false;
0072     }
0073     domElementKvtml.appendChild( currentElement );
0074 
0075     // lessons
0076     currentElement = m_domDoc.createElement( KVTML_LESSONS );
0077     writeLessons( m_doc->lesson(), currentElement );
0078     if ( currentElement.hasChildNodes() ) {
0079         domElementKvtml.appendChild( currentElement );
0080     }
0081 
0082     // types
0083     currentElement = m_domDoc.createElement( KVTML_WORDTYPES );
0084     writeWordTypes( currentElement, m_doc->wordTypeContainer() );
0085     if ( currentElement.hasChildNodes() ) {
0086         domElementKvtml.appendChild( currentElement );
0087     }
0088 
0089     // leitner boxes
0090     currentElement = m_domDoc.createElement( KVTML_LEITNERBOXES );
0091     writeLeitnerBoxes( currentElement, m_doc->leitnerContainer() );
0092     if ( currentElement.hasChildNodes() ) {
0093         domElementKvtml.appendChild( currentElement );
0094     }
0095 
0096     writeSynonymAntonymFalseFriend(domElementKvtml);
0097 
0098     m_domDoc.appendChild( domElementKvtml );
0099 
0100     return true;
0101 }
0102 
0103 bool KEduVocKvtml2Writer::writeInformation( QDomElement &informationElement, const QString &generator )
0104 {
0105     QDomElement currentElement;
0106     QDomText textNode;
0107 
0108     // generator
0109     informationElement.appendChild( newTextElement( KVTML_GENERATOR, generator ) );
0110 
0111     // title
0112     if ( !m_doc->title().isEmpty() ) {
0113         informationElement.appendChild( newTextElement( KVTML_TITLE, m_doc->title() ) );
0114     }
0115 
0116     // author
0117     if ( !m_doc->author().isEmpty() ) {
0118         informationElement.appendChild( newTextElement( KVTML_AUTHOR, m_doc->author() ) );
0119     }
0120 
0121     // author contact (mail/homepage)
0122     if ( !m_doc->authorContact().isEmpty() ) {
0123         informationElement.appendChild( newTextElement( KVTML_AUTHORCONTACT, m_doc->authorContact() ) );
0124     }
0125 
0126     // license
0127     if ( !m_doc->license().isEmpty() ) {
0128         informationElement.appendChild( newTextElement( KVTML_LICENSE, m_doc->license() ) );
0129     }
0130 
0131     // comment
0132     if ( !m_doc->documentComment().isEmpty() ) {
0133         informationElement.appendChild( newTextElement( KVTML_COMMENT, m_doc->documentComment() ) );
0134     }
0135 
0136     QDate today = QDate::currentDate();
0137     informationElement.appendChild( newTextElement( KVTML_DATE, today.toString(QStringLiteral("yyyy-MM-dd")) ) );
0138 
0139     // category
0140     if ( !m_doc->category().isEmpty() ) {
0141         informationElement.appendChild( newTextElement( KVTML_CATEGORY, m_doc->category() ) );
0142     }
0143 
0144     return true;
0145 }
0146 
0147 
0148 bool KEduVocKvtml2Writer::writeIdentifiers( QDomElement &identifiersElement )
0149 {
0150     for ( int i = 0; i < m_doc->identifierCount(); ++i ) {
0151         // create the node
0152         QDomElement identifier = m_domDoc.createElement( KVTML_IDENTIFIER );
0153 
0154         // set the id
0155         identifier.setAttribute( KVTML_ID, QString::number( i ) );
0156 
0157         // record the identifier as the locale for now
0158         // TODO: when support for more parts of the identifier is in the document class (name, type, etc.) store those here as well
0159         identifier.appendChild( newTextElement( KVTML_NAME, m_doc->identifier( i ).name() ) );
0160 
0161         identifier.appendChild( newTextElement( KVTML_LOCALE, m_doc->identifier( i ).locale() ) );
0162 
0163         // record articles
0164         QDomElement article = m_domDoc.createElement( KVTML_ARTICLE );
0165         writeArticle( article, i );
0166         if ( article.hasChildNodes() ) {
0167             identifier.appendChild( article );
0168         }
0169 
0170         // record personalpronouns
0171         QDomElement personalpronouns = m_domDoc.createElement( KVTML_PERSONALPRONOUNS );
0172         writePersonalPronoun( personalpronouns, m_doc->identifier(i).personalPronouns() );
0173         if ( personalpronouns.hasChildNodes() ) {
0174             identifier.appendChild( personalpronouns );
0175         }
0176 
0177         // tenses
0178         foreach(const QString &tense, m_doc->identifier(i).tenseList() ) {
0179             if ( !( tense.isNull() ) ) {
0180                 identifier.appendChild( newTextElement( KVTML_TENSE, tense ) );
0181             }
0182         }
0183         // add this identifier to the group
0184         identifiersElement.appendChild( identifier );
0185     }
0186     return true;
0187 }
0188 
0189 bool KEduVocKvtml2Writer::writeLessons( KEduVocLesson *parentLesson, QDomElement &lessonsElement )
0190 {
0191     // iterate over child lessons.
0192     // the first time this is called with the root lesson which does not have a <lesson> entry.
0193     for( int i = 0; i < parentLesson->childContainerCount(); i++ ) {
0194         KEduVocLesson *lesson = static_cast<KEduVocLesson*>(parentLesson->childContainer(i));
0195         // make lesson element
0196         QDomElement thisLessonElement = m_domDoc.createElement( KVTML_CONTAINER );
0197 
0198         // add a name
0199         thisLessonElement.appendChild( newTextElement( KVTML_NAME, lesson->name() ) );
0200 
0201         // add a inquery tag
0202         if ( lesson->inPractice() ) {
0203             thisLessonElement.appendChild( newTextElement( KVTML_INPRACTICE, KVTML_TRUE ) );
0204         }
0205 
0206         // child lessons
0207         writeLessons(lesson, thisLessonElement);
0208 
0209         // child entries
0210         foreach(KEduVocExpression *entry, lesson->entries()) {
0211             QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0212             entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
0213             thisLessonElement.appendChild(entryElement);
0214         }
0215         lessonsElement.appendChild( thisLessonElement );
0216     }
0217     return true;
0218 }
0219 
0220 
0221 
0222 void KEduVocKvtml2Writer::writeSynonymAntonymFalseFriend(QDomElement & parentElement)
0223 {
0224     QList< KEduVocTranslation* > currentList;
0225     QDomElement synonymElement;
0226     // synonym, antonym, false friend
0227     for(int type = KEduVocTranslation::Synonym; type <= KEduVocTranslation::FalseFriend; type++) {
0228         switch (type) {
0229             case KEduVocTranslation::Synonym:
0230                 synonymElement = m_domDoc.createElement( KVTML_SYNONYM );
0231                 currentList = m_synonyms;
0232                 break;
0233             case KEduVocTranslation::Antonym:
0234                 synonymElement = m_domDoc.createElement( KVTML_ANTONYM );
0235                 currentList = m_antonyms;
0236                 break;
0237             case KEduVocTranslation::FalseFriend:
0238                 synonymElement = m_domDoc.createElement( KVTML_FALSEFRIEND );
0239                 currentList = m_falseFriends;
0240                 break;
0241         }
0242 
0243         while (!currentList.isEmpty()) {
0244             // after writing a translation, remove it from the list
0245             KEduVocTranslation* translation = currentList.takeFirst();
0246 
0247 
0248             QDomElement relatedElement;
0249             QList <KEduVocTranslation*> list;
0250             switch (type) {
0251             case KEduVocTranslation::Synonym:
0252                 list = translation->synonyms();
0253                 break;
0254             case KEduVocTranslation::Antonym:
0255                 list = translation->antonyms();
0256                 break;
0257             case KEduVocTranslation::FalseFriend:
0258                 list = translation->falseFriends();
0259                 break;
0260             }
0261             foreach (KEduVocTranslation* synonym, list) {
0262                 // if it is not in the list it has already been written and we can move on
0263                 if (currentList.contains(synonym)) {
0264                     relatedElement = m_domDoc.createElement( KVTML_PAIR );
0265 
0266             // fill the entry element but only add later if it is valid
0267             QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0268             entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(translation->entry())) );
0269             // find out which id that is... silly
0270             foreach(int index, translation->entry()->translationIndices()) {
0271             if (translation->entry()->translation(index) == translation) {
0272                 // create <translation id="123">
0273                 QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
0274                 translationElement.setAttribute( KVTML_ID, QString::number(index) );
0275                 entryElement.appendChild(translationElement);
0276                 break;
0277             }
0278             }
0279 
0280                     relatedElement.appendChild(entryElement);
0281 
0282 
0283                     QDomElement partnerElement = m_domDoc.createElement( KVTML_ENTRY );
0284                     partnerElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(synonym->entry())) );
0285                     // find out which id that is
0286                     foreach(int index, synonym->entry()->translationIndices()) {
0287                         if (synonym->entry()->translation(index) == synonym) {
0288                             // create <translation id="123">
0289                             QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
0290                             translationElement.setAttribute( KVTML_ID, QString::number(index) );
0291                             partnerElement.appendChild(translationElement);
0292                             break;
0293                         }
0294                     }
0295                     relatedElement.appendChild( partnerElement );
0296             synonymElement.appendChild(relatedElement);
0297                 }
0298             }
0299 
0300         }
0301         if (synonymElement.hasChildNodes()) {
0302             parentElement.appendChild( synonymElement );
0303         }
0304     } // iterate over types
0305 }
0306 /*
0307 bool KEduVocKvtml2Writer::writeRelated(QDomElement & parentElement, QList< KEduVocTranslation * > relatedList)
0308 {
0309     foreach (KEduVocTranslation* synonym, translation->synonyms()) {
0310         QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0311         entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(translation->entry())) );
0312 
0313         // find out which id that is... silly
0314         foreach(int index, translation->entry()->translationIndices()) {
0315             if (translation->entry()->translation(index) == translation) {
0316                 // create <translation id="123">
0317                 QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
0318                 translationElement.setAttribute( KVTML_ID, QString::number(index) );
0319                 entryElement.appendChild(translationElement);
0320             }
0321         }
0322         parentElement.appendChild( entryElement );
0323     }
0324 }*/
0325 
0326 bool KEduVocKvtml2Writer::writeArticle( QDomElement &articleElement, int language )
0327 {
0328     ///@todo only write if not empty
0329     QMap<int, KEduVocWordFlag::Flags> numbers;
0330     numbers[0] = KEduVocWordFlag::Singular;
0331     numbers[1] = KEduVocWordFlag::Dual;
0332     numbers[2] = KEduVocWordFlag::Plural;
0333     QMap<int, KEduVocWordFlag::Flags> genders;
0334     genders[0] = KEduVocWordFlag::Masculine;
0335     genders[1] = KEduVocWordFlag::Feminine;
0336     genders[2] = KEduVocWordFlag::Neuter;
0337     QMap<int, KEduVocWordFlag::Flags> defs;
0338     defs[0] = KEduVocWordFlag::Definite;
0339     defs[1] = KEduVocWordFlag::Indefinite;
0340 
0341     for (int num = 0; num <= 2; num++)
0342     {
0343         QDomElement numberElement = m_domDoc.createElement( KVTML_GRAMMATICAL_NUMBER[num] );
0344 
0345         for (int def = 0; def <= 1; def++) {
0346             QDomElement defElement = m_domDoc.createElement( KVTML_GRAMMATICAL_DEFINITENESS[def] );
0347 
0348             for (int gen = 0; gen <= 2; gen++)
0349             {
0350                 QString articleString = m_doc->identifier(language).article().article(numbers[num] | genders[gen] | defs[def]);
0351                 if ( !articleString.isEmpty() ) {
0352                     defElement.appendChild( newTextElement( KVTML_GRAMMATICAL_GENDER[gen], articleString ) );
0353                 }
0354             }
0355             if ( defElement.hasChildNodes() ) {
0356                 numberElement.appendChild( defElement );
0357             }
0358         }
0359         if ( numberElement.hasChildNodes() ) {
0360             articleElement.appendChild( numberElement );
0361         }
0362     }
0363     return true;
0364 }
0365 
0366 
0367 bool KEduVocKvtml2Writer::writeWordTypes( QDomElement &typesElement, KEduVocWordType* parentContainer )
0368 {
0369     foreach( KEduVocContainer* container, parentContainer->childContainers() ) {
0370         KEduVocWordType* wordType = static_cast<KEduVocWordType*>(container);
0371 
0372         QDomElement typeDefinitionElement = m_domDoc.createElement( KVTML_CONTAINER );
0373         typeDefinitionElement.appendChild( newTextElement( KVTML_NAME, wordType->name() ) );
0374 
0375         if (wordType->wordType().testFlag(KEduVocWordFlag::Noun))
0376         {
0377             if (wordType->wordType().testFlag(KEduVocWordFlag::Masculine))
0378                 typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_MALE ) );
0379 
0380             else if (wordType->wordType().testFlag(KEduVocWordFlag::Feminine))
0381                 typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_FEMALE ) );
0382 
0383             else if (wordType->wordType().testFlag(KEduVocWordFlag::Neuter))
0384                 typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN_NEUTRAL ) );
0385             else
0386                 typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_NOUN ) );
0387         }
0388         else if (wordType->wordType().testFlag(KEduVocWordFlag::Verb))
0389             typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_VERB ) );
0390 
0391         else if (wordType->wordType().testFlag(KEduVocWordFlag::Adjective))
0392             typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_ADJECTIVE ) );
0393 
0394         else if (wordType->wordType().testFlag(KEduVocWordFlag::Adverb))
0395             typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_ADVERB ) );
0396 
0397         else if (wordType->wordType().testFlag(KEduVocWordFlag::Conjunction))
0398             typeDefinitionElement.appendChild( newTextElement( KVTML_SPECIALWORDTYPE, KVTML_SPECIALWORDTYPE_CONJUNCTION ) );
0399 
0400 
0401 // child entries
0402 
0403         // child entries
0404         foreach(KEduVocExpression *entry, wordType->entries()) {
0405             QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0406             entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
0407             for(int translation = 0; translation<m_doc->identifierCount(); translation++) {
0408                 if (entry->translation(translation)->wordType()== wordType) {
0409                     QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
0410                     // create <translation id="123">
0411                     translationElement.setAttribute( KVTML_ID, QString::number(translation) );
0412                     // append both
0413                     entryElement.appendChild(translationElement);
0414                 }
0415             }
0416             typeDefinitionElement.appendChild( entryElement );
0417         }
0418 
0419         writeWordTypes( typeDefinitionElement, wordType );
0420 
0421         typesElement.appendChild( typeDefinitionElement );
0422     }
0423     return true;
0424 }
0425 
0426 bool KEduVocKvtml2Writer::writeLeitnerBoxes( QDomElement &leitnerParentElement, KEduVocLeitnerBox* parentContainer )
0427 {
0428     foreach( KEduVocContainer* container, parentContainer->childContainers() ) {
0429         KEduVocLeitnerBox* leitnerBox = static_cast<KEduVocLeitnerBox*>(container);
0430 
0431         QDomElement containerElement = m_domDoc.createElement( KVTML_CONTAINER );
0432         containerElement.appendChild( newTextElement( KVTML_NAME, leitnerBox->name() ) );
0433 
0434         // child entries
0435         foreach(KEduVocExpression *entry, leitnerBox->entries()) {
0436             QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0437             entryElement.setAttribute( KVTML_ID, QString::number(m_allEntries.indexOf(entry)) );
0438             for(int translation = 0; translation<m_doc->identifierCount(); translation++) {
0439                 if (entry->translation(translation)->leitnerBox()== leitnerBox) {
0440                     QDomElement translationElement = m_domDoc.createElement( KVTML_TRANSLATION );
0441                     // create <translation id="123">
0442                     translationElement.setAttribute( KVTML_ID, QString::number(translation) );
0443                     // append both
0444                     entryElement.appendChild(translationElement);
0445                 }
0446             }
0447             containerElement.appendChild( entryElement );
0448         }
0449 
0450         leitnerParentElement.appendChild( containerElement );
0451     }
0452     return true;
0453 }
0454 
0455 bool KEduVocKvtml2Writer::writeEntries( QDomElement &entriesElement )
0456 {
0457     m_allEntries = m_doc->lesson()->entries(KEduVocLesson::Recursive);
0458 
0459     // loop through entries
0460     for ( int i = 0; i < m_allEntries.count(); ++i ) {
0461         KEduVocExpression *thisEntry = m_allEntries.value(i);
0462 
0463         // write entry tag
0464         QDomElement entryElement = m_domDoc.createElement( KVTML_ENTRY );
0465 
0466         // add id
0467         entryElement.setAttribute( KVTML_ID, QString::number( i ) );
0468 
0469         // write deactivated
0470         if(!thisEntry->isActive()) {
0471             entryElement.appendChild( newTextElement( KVTML_DEACTIVATED, KVTML_TRUE ) );
0472         }
0473 
0474         // loop through translations
0475         foreach( int trans, thisEntry->translationIndices() ) {
0476             // write translations
0477             QDomElement translation = m_domDoc.createElement( KVTML_TRANSLATION );
0478             translation.setAttribute( KVTML_ID, QString::number( trans ) );
0479             writeTranslation( translation, thisEntry->translation( trans ) );
0480             entryElement.appendChild( translation );
0481         }
0482         // add this entry to the entriesElement
0483         entriesElement.appendChild( entryElement );
0484     }
0485     return true;
0486 }
0487 
0488 
0489 bool KEduVocKvtml2Writer::writeTranslation( QDomElement &translationElement, KEduVocTranslation* translation )
0490 {
0491     // so far only for KEduVocWord - text and grades
0492     translation->toKVTML2(translationElement);
0493 
0494     // comparison
0495     if ( !(translation->comparativeForm().text().isEmpty() || translation->superlativeForm().text().isEmpty())) {
0496         qDebug() << "Write comp";
0497         QDomElement comparisonElement = m_domDoc.createElement( KVTML_COMPARISON );
0498         translationElement.appendChild(comparisonElement);
0499 
0500         QDomElement comparativeElement = m_domDoc.createElement( KVTML_COMPARATIVE );
0501         comparisonElement.appendChild(comparativeElement);
0502         translation->comparativeForm().toKVTML2(comparativeElement);
0503 
0504         QDomElement superlativeElement = m_domDoc.createElement( KVTML_SUPERLATIVE );
0505         comparisonElement.appendChild(superlativeElement);
0506         translation->superlativeForm().toKVTML2(superlativeElement);
0507     }
0508 
0509     if (translation->article().practiceCount() != 0) {
0510         QDomElement articleElement = m_domDoc.createElement( KVTML_ARTICLE );
0511         translation->article().toKVTML2(articleElement);
0512         translationElement.appendChild(articleElement);
0513     }
0514 
0515     // multiplechoice
0516     if (!translation->getMultipleChoice().isEmpty()) {
0517         QDomElement multipleChoiceElement = m_domDoc.createElement( KVTML_MULTIPLECHOICE );
0518         writeMultipleChoice( multipleChoiceElement, translation );
0519         translationElement.appendChild( multipleChoiceElement );
0520     }
0521 
0522     // image
0523     if ( !translation->imageUrl().isEmpty() ) {
0524         QString urlString;
0525         const QUrl docDirUrl = m_doc->url().adjusted(QUrl::RemoveFilename);
0526         if ( docDirUrl.isParentOf( translation->imageUrl()) ) {
0527             // try to save as relative url
0528             const QDir dir( docDirUrl.toLocalFile() );
0529             urlString = QUrl::fromLocalFile(
0530                 dir.relativeFilePath( translation->imageUrl().toLocalFile() )
0531             ).url();
0532         } else {
0533             urlString =  translation->imageUrl().url();
0534         }
0535         translationElement.appendChild( newTextElement( KVTML_IMAGE, urlString ) );
0536     }
0537 
0538     // sound
0539     if ( !translation->soundUrl().isEmpty() ) {
0540         QString urlString;
0541         const QUrl docDirUrl = m_doc->url().adjusted(QUrl::RemoveFilename);
0542         if ( docDirUrl.isParentOf( translation->soundUrl()) ) {
0543             // try to save as relative url
0544             const QDir dir( docDirUrl.toLocalFile() );
0545             urlString = QUrl::fromLocalFile(
0546                 dir.relativeFilePath( translation->soundUrl().toLocalFile() )
0547             ).url();
0548         } else {
0549             urlString = translation->soundUrl().url();
0550         }
0551         translationElement.appendChild( newTextElement( KVTML_SOUND, urlString ) );
0552     }
0553 
0554 
0555     // synonym, antonym, false friend
0556     // add to the list if it has any, write later since we want them separate
0557     if (!translation->synonyms().isEmpty()) {
0558         m_synonyms.append(translation);
0559     }
0560     if (!translation->antonyms().isEmpty()) {
0561         m_antonyms.append(translation);
0562     }
0563     if (!translation->falseFriends().isEmpty()) {
0564         m_falseFriends.append(translation);
0565     }
0566     return true;
0567 }
0568 
0569 
0570 
0571     ///@todo write false friends
0572     // <falsefriend fromid="0"></falsefriend>
0573     // loop through the identifiers
0574 //     for ( int i = 0; i < m_doc->identifierCount(); ++i ) {
0575 //         // see if this identifier has a falsefriend in this translation
0576 //         QString thisFriend = translation->falseFriend( i );
0577 //         if ( !thisFriend.isEmpty() ) {
0578 //             // if so, create it, and set the fromid to i
0579 //             QDomElement thisFriendElement = newTextElement( KVTML_FALSEFRIEND, thisFriend );
0580 //             thisFriendElement.setAttribute( KVTML_FROMID, QString::number( i ) );
0581 //             translationElement.appendChild( thisFriendElement );
0582 //         }
0583 //     }
0584 
0585 bool KEduVocKvtml2Writer::writeMultipleChoice( QDomElement &multipleChoiceElement, KEduVocTranslation* translation )
0586 /*
0587  <multiplechoice>
0588    <choice>good</choice>
0589    <choice>better</choice>
0590    <choice>best</choice>
0591    <choice>best 2</choice>
0592    <choice>best 3</choice>
0593  </multiplechoice>
0594 */
0595 {
0596     foreach (const QString &choice, translation->getMultipleChoice()) {
0597         multipleChoiceElement.appendChild( newTextElement( KVTML_CHOICE, choice ) );
0598     }
0599     return true;
0600 }
0601 
0602 QDomElement KEduVocKvtml2Writer::newTextElement( const QString &elementName, const QString &text )
0603 {
0604     QDomElement retval = m_domDoc.createElement( elementName );
0605     QDomText textNode = m_domDoc.createTextNode( text );
0606     retval.appendChild( textNode );
0607     return retval;
0608 }
0609 
0610 bool KEduVocKvtml2Writer::writePersonalPronoun(QDomElement & pronounElement, const KEduVocPersonalPronoun & pronoun)
0611 {
0612     // general pronoun properties
0613     if ( pronoun.maleFemaleDifferent() ) {
0614         pronounElement.appendChild( m_domDoc.createElement( KVTML_THIRD_PERSON_MALE_FEMALE_DIFFERENT ) );
0615     }
0616     if ( pronoun.neutralExists() ) {
0617         pronounElement.appendChild( m_domDoc.createElement( KVTML_THIRD_PERSON_NEUTRAL_EXISTS ) );
0618     }
0619     if ( pronoun.dualExists() ) {
0620         pronounElement.appendChild( m_domDoc.createElement( KVTML_DUAL_EXISTS ) );
0621     }
0622 
0623 
0624     QMap<int, KEduVocWordFlag::Flags> numbers;
0625     numbers[0] = KEduVocWordFlag::Singular;
0626     numbers[1] = KEduVocWordFlag::Dual;
0627     numbers[2] = KEduVocWordFlag::Plural;
0628     QMap<int, KEduVocWordFlag::Flags> persons;
0629     persons[0] = KEduVocWordFlag::First;
0630     persons[1] = KEduVocWordFlag::Second;
0631     persons[2] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Masculine);
0632     persons[3] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Feminine);
0633     persons[4] = (KEduVocWordFlag::Flags)((int)KEduVocWordFlag::Third | (int)KEduVocWordFlag::Neuter);
0634 
0635 
0636 
0637     // the actual pronouns
0638     for ( int num = 0; num < 3; num++ ) {
0639         QDomElement numberElement = m_domDoc.createElement( KVTML_GRAMMATICAL_NUMBER[num] );
0640         for ( int person = 0; person < 5; person++ ) {
0641             QString pronounString = pronoun.personalPronoun(numbers[num] | persons[person]);
0642             if (!pronounString.isEmpty()) {
0643                 numberElement.appendChild( newTextElement( KVTML_GRAMMATICAL_PERSON[person], pronounString ));
0644             }
0645         }
0646         if (numberElement.hasChildNodes()) {
0647             pronounElement.appendChild( numberElement );
0648         }
0649     }
0650     return true;
0651 }
0652 
0653 void KEduVocKvtml2Writer::appendTextElement(QDomElement & parent, const QString & elementName, const QString & text)
0654 {
0655     // empty will never be written
0656     if (text.isEmpty()) {
0657         return;
0658     }
0659 
0660     QDomDocument domDoc = parent.ownerDocument();
0661     QDomElement element = domDoc.createElement( elementName );
0662     parent.appendChild( element );
0663     QDomText textNode = domDoc.createTextNode( text );
0664     element.appendChild( textNode );
0665 }