File indexing completed on 2024-05-19 05:05:34
0001 /*************************************************************************** 0002 * SPDX-License-Identifier: GPL-2.0-or-later 0003 * * 0004 * SPDX-FileCopyrightText: 2004-2023 Thomas Fischer <fischer@unix-ag.uni-kl.de> 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, see <https://www.gnu.org/licenses/>. * 0018 ***************************************************************************/ 0019 0020 #include "fileexporterris.h" 0021 0022 #include <QIODevice> 0023 #include <QRegularExpression> 0024 #include <QStringList> 0025 0026 #include <Entry> 0027 #include <KBibTeX> 0028 #include "fileexporter_p.h" 0029 #include "logging_io.h" 0030 0031 class FileExporterRIS::Private 0032 { 0033 private: 0034 FileExporterRIS *parent; 0035 0036 public: 0037 Private(FileExporterRIS *p) 0038 : parent(p) 0039 { 0040 // nothing 0041 } 0042 0043 bool writeEntry(QTextStream &stream, const QSharedPointer<const Entry> entry) 0044 { 0045 bool result = true; 0046 QString type = entry->type(); 0047 0048 if (type == Entry::etBook) 0049 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("BOOK")); 0050 else if (type == Entry::etInBook) 0051 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("CHAP")); 0052 else if (type == Entry::etInProceedings) 0053 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("CONF")); 0054 else if (type == Entry::etArticle) 0055 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("JOUR")); 0056 else if (type == Entry::etTechReport) 0057 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("RPRT")); 0058 else if (type == Entry::etPhDThesis || type == Entry::etMastersThesis) 0059 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("THES")); 0060 else if (type == Entry::etUnpublished) 0061 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("UNPB")); 0062 else 0063 writeKeyValue(stream, QStringLiteral("TY"), QStringLiteral("GEN")); 0064 0065 writeKeyValue(stream, QStringLiteral("ID"), entry->id()); 0066 0067 QString year, month; 0068 0069 for (Entry::ConstIterator it = entry->constBegin(); result && it != entry->constEnd(); ++it) { 0070 const QString &key = it.key(); 0071 const Value &value = it.value(); 0072 0073 if (key.startsWith(QStringLiteral("RISfield_"))) 0074 result &= writeKeyValue(stream, key.right(2), PlainTextValue::text(value)); 0075 else if (key == Entry::ftAuthor) { 0076 for (Value::ConstIterator it = value.constBegin(); result && it != value.constEnd(); ++it) { 0077 QSharedPointer<const Person> person = (*it).dynamicCast<const Person>(); 0078 if (!person.isNull()) 0079 result &= writeKeyValue(stream, QStringLiteral("AU"), PlainTextValue::text(**it)); 0080 else 0081 qCWarning(LOG_KBIBTEX_IO) << "Cannot write value " << PlainTextValue::text(**it) << " for field AU (author), not supported by RIS format"; 0082 } 0083 } else if (key.toLower() == Entry::ftEditor) { 0084 for (Value::ConstIterator it = value.constBegin(); result && it != value.constEnd(); ++it) { 0085 QSharedPointer<const Person> person = (*it).dynamicCast<const Person>(); 0086 if (!person.isNull()) 0087 result &= writeKeyValue(stream, QStringLiteral("ED"), PlainTextValue::text(**it)); 0088 else 0089 qCWarning(LOG_KBIBTEX_IO) << "Cannot write value " << PlainTextValue::text(**it) << " for field ED (editor), not supported by RIS format"; 0090 } 0091 } else if (key == Entry::ftTitle) 0092 result &= writeKeyValue(stream, QStringLiteral("TI"), PlainTextValue::text(value)); 0093 else if (key == Entry::ftBookTitle) 0094 result &= writeKeyValue(stream, QStringLiteral("BT"), PlainTextValue::text(value)); 0095 else if (key == Entry::ftSeries) 0096 result &= writeKeyValue(stream, QStringLiteral("T3"), PlainTextValue::text(value)); 0097 else if (key == Entry::ftJournal) 0098 result &= writeKeyValue(stream, QStringLiteral("JO"), PlainTextValue::text(value)); ///< "JF" instead? 0099 else if (key == Entry::ftChapter) 0100 result &= writeKeyValue(stream, QStringLiteral("CP"), PlainTextValue::text(value)); 0101 else if (key == Entry::ftISSN) 0102 result &= writeKeyValue(stream, QStringLiteral("SN"), PlainTextValue::text(value)); 0103 else if (key == Entry::ftISBN) 0104 result &= writeKeyValue(stream, QStringLiteral("SN"), PlainTextValue::text(value)); 0105 else if (key == Entry::ftSchool) /// == "institution" 0106 result &= writeKeyValue(stream, QStringLiteral("IN"), PlainTextValue::text(value)); 0107 else if (key == Entry::ftVolume) 0108 result &= writeKeyValue(stream, QStringLiteral("VL"), PlainTextValue::text(value)); 0109 else if (key == Entry::ftNumber) /// == "issue" 0110 result &= writeKeyValue(stream, QStringLiteral("IS"), PlainTextValue::text(value)); 0111 else if (key == Entry::ftNote) 0112 result &= writeKeyValue(stream, QStringLiteral("N1"), PlainTextValue::text(value)); 0113 else if (key == Entry::ftAbstract) 0114 result &= writeKeyValue(stream, QStringLiteral("N2"), PlainTextValue::text(value)); ///< "AB" instead? 0115 else if (key == Entry::ftPublisher) 0116 result &= writeKeyValue(stream, QStringLiteral("PB"), PlainTextValue::text(value)); 0117 else if (key == Entry::ftLocation) 0118 result &= writeKeyValue(stream, QStringLiteral("CY"), PlainTextValue::text(value)); 0119 else if (key == Entry::ftDOI) 0120 result &= writeKeyValue(stream, QStringLiteral("DO"), PlainTextValue::text(value)); 0121 else if (key == Entry::ftKeywords) 0122 result &= writeKeyValue(stream, QStringLiteral("KW"), PlainTextValue::text(value)); 0123 else if (key == Entry::ftYear) 0124 year = PlainTextValue::text(value); 0125 else if (key == Entry::ftMonth) 0126 month = PlainTextValue::text(value); 0127 else if (key == Entry::ftAddress) 0128 result &= writeKeyValue(stream, QStringLiteral("AD"), PlainTextValue::text(value)); 0129 else if (key == Entry::ftUrl) { 0130 // FIXME one "UR" line per URL 0131 // FIXME for local files, use "L1" 0132 result &= writeKeyValue(stream, QStringLiteral("UR"), PlainTextValue::text(value)); 0133 } else if (key == Entry::ftPages) { 0134 static const QRegularExpression splitRegExp(QString(QStringLiteral("-{1,2}|%1")).arg(QChar(0x2013))); 0135 QStringList pageRange = PlainTextValue::text(value).split(splitRegExp); 0136 if (pageRange.count() == 2) { 0137 result &= writeKeyValue(stream, QStringLiteral("SP"), pageRange[ 0 ]); 0138 result &= writeKeyValue(stream, QStringLiteral("EP"), pageRange[ 1 ]); 0139 } 0140 } 0141 } 0142 0143 if (!year.isEmpty() || !month.isEmpty()) { 0144 int monthAsInt = -1; 0145 for (int i = 0; monthAsInt < 0 && i < 12; ++i) 0146 if (KBibTeX::MonthsTriple[i] == month) 0147 monthAsInt = i + 1; 0148 if (monthAsInt > 0) 0149 result &= writeKeyValue(stream, QStringLiteral("PY"), QString(QStringLiteral("%1/%2//")).arg(year).arg(monthAsInt, 2, 10, QLatin1Char('0'))); 0150 else 0151 result &= writeKeyValue(stream, QStringLiteral("PY"), QString(QStringLiteral("%1///%2")).arg(year, month)); 0152 } 0153 0154 result &= writeKeyValue(stream, QStringLiteral("ER"), QString()); 0155 #if QT_VERSION >= 0x050e00 0156 stream << Qt::endl; 0157 #else // QT_VERSION < 0x050e00 0158 stream << endl; 0159 #endif // QT_VERSION >= 0x050e00 0160 0161 return result; 0162 } 0163 0164 bool writeKeyValue(QTextStream &stream, const QString &key, const QString &value) 0165 { 0166 stream << key << " - "; 0167 if (!value.isEmpty()) 0168 stream << value; 0169 #if QT_VERSION >= 0x050e00 0170 stream << Qt::endl; 0171 #else // QT_VERSION < 0x050e00 0172 stream << endl; 0173 #endif // QT_VERSION >= 0x050e00 0174 0175 return true; 0176 } 0177 }; 0178 0179 FileExporterRIS::FileExporterRIS(QObject *parent) 0180 : FileExporter(parent), d(new Private(this)) 0181 { 0182 /// nothing 0183 } 0184 0185 FileExporterRIS::~FileExporterRIS() 0186 { 0187 delete d; 0188 } 0189 0190 bool FileExporterRIS::save(QIODevice *iodevice, const QSharedPointer<const Element> &element, const File *bibtexfile) 0191 { 0192 Q_UNUSED(bibtexfile) 0193 0194 check_if_iodevice_invalid(iodevice); 0195 0196 bool result = false; 0197 QTextStream stream(iodevice); 0198 0199 const QSharedPointer<const Entry> &entry = element.dynamicCast<const Entry>(); 0200 if (!entry.isNull()) 0201 result = d->writeEntry(stream, entry); 0202 0203 return result; 0204 } 0205 0206 bool FileExporterRIS::save(QIODevice *iodevice, const File *bibtexfile) 0207 { 0208 check_if_bibtexfile_or_iodevice_invalid(bibtexfile, iodevice); 0209 0210 bool result = true; 0211 QTextStream stream(iodevice); 0212 0213 for (File::ConstIterator it = bibtexfile->constBegin(); it != bibtexfile->constEnd() && result; ++it) { 0214 const QSharedPointer<const Entry> &entry = (*it).dynamicCast<Entry>(); 0215 if (!entry.isNull()) { 0216 const QSharedPointer<const Entry> resolvedEntry(entry->resolveCrossref(bibtexfile)); 0217 result |= d->writeEntry(stream, resolvedEntry); 0218 } 0219 } 0220 0221 return result; 0222 }