File indexing completed on 2024-05-12 05:10:08

0001 /*************************************************************************
0002     Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include <config.h>
0026 
0027 #include "bibtexmlexporter.h"
0028 #include "../utils/bibtexhandler.h"
0029 #include "../fieldformat.h"
0030 #include "../core/filehandler.h"
0031 #include "tellico_xml.h"
0032 #include "../utils/stringset.h"
0033 #include "../tellico_debug.h"
0034 
0035 #include <KLocalizedString>
0036 
0037 #include <QDomDocument>
0038 #include <QTextCodec>
0039 
0040 using namespace Tellico;
0041 using Tellico::Export::BibtexmlExporter;
0042 
0043 BibtexmlExporter::BibtexmlExporter(Data::CollPtr coll_) : Exporter(coll_) {
0044 }
0045 
0046 QString BibtexmlExporter::formatString() const {
0047   return QStringLiteral("Bibtexml");
0048 }
0049 
0050 QString BibtexmlExporter::fileFilter() const {
0051   return i18n("Bibtexml Files") + QLatin1String(" (*.xml)") + QLatin1String(";;") + i18n("All Files") + QLatin1String(" (*)");
0052 }
0053 
0054 bool BibtexmlExporter::exec() {
0055   const QString text = this->text();
0056   return text.isEmpty() ? false : FileHandler::writeTextURL(url(), text, options() & ExportUTF8, options() & Export::ExportForce);
0057 }
0058 
0059 QString BibtexmlExporter::text() {
0060   Data::CollPtr c = collection();
0061   if(!c || c->type() != Data::Collection::Bibtex) {
0062     return QString();
0063   }
0064 
0065 // there are some special fields
0066 // the entry-type specifies the entry type - book, inproceedings, whatever
0067   QString typeField;
0068 // the key specifies the cite-key
0069   QString keyField;
0070 
0071   const QString bibtex = QStringLiteral("bibtex");
0072 // keep a list of all the 'ordinary' fields to iterate through later
0073   Data::FieldList fields;
0074   foreach(Data::FieldPtr it, this->fields()) {
0075     QString bibtexField = it->property(bibtex);
0076     if(bibtexField == QLatin1String("entry-type")) {
0077       typeField = it->name();
0078     } else if(bibtexField == QLatin1String("key")) {
0079       keyField = it->name();
0080     } else if(!bibtexField.isEmpty()) {
0081       fields.append(it);
0082     }
0083   }
0084 
0085   QDomImplementation impl;
0086   QDomDocumentType doctype = impl.createDocumentType(QStringLiteral("file"),
0087                                                      QString(),
0088                                                      XML::dtdBibtexml);
0089   //default namespace
0090   const QString& ns = XML::nsBibtexml;
0091 
0092   QDomDocument dom = impl.createDocument(ns, QStringLiteral("file"), doctype);
0093 
0094   // root element
0095   QDomElement root = dom.documentElement();
0096 
0097   QString encodeStr = QStringLiteral("version=\"1.0\" encoding=\"");
0098   if(options() & Export::ExportUTF8) {
0099     encodeStr += QLatin1String("UTF-8");
0100   } else {
0101     encodeStr += QLatin1String(QTextCodec::codecForLocale()->name());
0102   }
0103   encodeStr += QLatin1Char('"');
0104 
0105   // createDocument creates a root node, insert the processing instruction before it
0106   dom.insertBefore(dom.createProcessingInstruction(QStringLiteral("xml"), encodeStr), root);
0107   QString comment = QLatin1String("Generated by Tellico ") + QLatin1String(TELLICO_VERSION);
0108   dom.insertBefore(dom.createComment(comment), root);
0109 
0110   FieldFormat::Request format = (options() & Export::ExportFormatted ?
0111                                                 FieldFormat::ForceFormat :
0112                                                 FieldFormat::AsIsFormat);
0113 
0114   StringSet usedKeys;
0115   QString type, key, newKey, value, elemName, parElemName;
0116   QDomElement btElem, entryElem, parentElem, fieldElem;
0117   foreach(Data::EntryPtr entryIt, entries()) {
0118     key = entryIt->field(keyField);
0119     if(key.isEmpty()) {
0120       key = BibtexHandler::bibtexKey(entryIt);
0121     }
0122     newKey = key;
0123     char c = 'a';
0124     while(usedKeys.has(newKey)) {
0125       // duplicate found!
0126       newKey = key + QLatin1Char(c);
0127       ++c;
0128     }
0129     key = newKey;
0130     usedKeys.add(key);
0131 
0132     btElem = dom.createElement(QStringLiteral("entry"));
0133     btElem.setAttribute(QStringLiteral("id"), key);
0134     root.appendChild(btElem);
0135 
0136     type = entryIt->field(typeField);
0137     if(type.isEmpty()) {
0138       myWarning() << "the entry for '" << entryIt->title()
0139                  << "' has no entry-type, skipping it!";
0140       continue;
0141     }
0142 
0143     entryElem = dom.createElement(type);
0144     btElem.appendChild(entryElem);
0145 
0146     // now iterate over attributes
0147     foreach(Data::FieldPtr field, fields) {
0148       value = entryIt->formattedField(field, format);
0149       if(value.isEmpty()) {
0150         continue;
0151       }
0152 
0153 /* Bibtexml has special container elements for titles, authors, editors, and keywords
0154    I'm going to ignore the titlelist element for right now. All authors are contained in
0155    an authorlist element, editors in an editorlist element, and keywords are in a
0156    keywords element, and themselves as a keyword. Also, Bibtexml can format names
0157    similar to docbook, with first, middle, last, etc elements. I'm going to ignore that
0158    for now, too.*/
0159       elemName = field->property(bibtex);
0160       // split text for author, editor, and keywords
0161       if(elemName == QLatin1String("author") ||
0162          elemName == QLatin1String("editor") ||
0163          elemName == QLatin1String("keywords")) {
0164         if(elemName == QLatin1String("author")) {
0165           parElemName = QStringLiteral("authorlist");
0166         } else if(elemName == QLatin1String("editor")) {
0167           parElemName = QStringLiteral("editorlist");
0168         } else { // keywords
0169           parElemName = QStringLiteral("keywords");
0170           elemName = QStringLiteral("keyword");
0171         }
0172 
0173         parentElem = dom.createElement(parElemName);
0174         const QStringList values = FieldFormat::splitValue(entryIt->formattedField(field, format));
0175         foreach(const QString& value, values) {
0176           fieldElem = dom.createElement(elemName);
0177           fieldElem.appendChild(dom.createTextNode(value));
0178           parentElem.appendChild(fieldElem);
0179         }
0180         if(parentElem.hasChildNodes()) {
0181           entryElem.appendChild(parentElem);
0182         }
0183       } else {
0184         fieldElem = dom.createElement(elemName);
0185         fieldElem.appendChild(dom.createTextNode(value));
0186         entryElem.appendChild(fieldElem);
0187       }
0188     }
0189   }
0190 
0191   return dom.toString();
0192 }