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 "fileexporterpdf.h" 0021 0022 #include <QFile> 0023 #include <QStringList> 0024 #include <QUrl> 0025 #include <QTextStream> 0026 #include <QDir> 0027 0028 #include <KBibTeX> 0029 #include <Preferences> 0030 #include <Element> 0031 #include <Entry> 0032 #include "fileinfo.h" 0033 #include "fileexporterbibtex.h" 0034 #include "fileexporter_p.h" 0035 #include "logging_io.h" 0036 0037 FileExporterPDF::FileExporterPDF(QObject *parent) 0038 : FileExporterToolchain(parent) 0039 { 0040 m_fileBasename = QStringLiteral("bibtex-to-pdf"); 0041 m_fileStem = tempDir.path() + QDir::separator() + m_fileBasename; 0042 0043 setFileEmbedding(FileExporterPDF::FileEmbedding::BibTeXFileAndReferences); 0044 } 0045 0046 FileExporterPDF::~FileExporterPDF() 0047 { 0048 /// nothing 0049 } 0050 0051 bool FileExporterPDF::save(QIODevice *iodevice, const File *bibtexfile) 0052 { 0053 check_if_bibtexfile_or_iodevice_invalid(bibtexfile, iodevice); 0054 0055 bool result = false; 0056 m_embeddedFileList.clear(); 0057 if (m_fileEmbeddings.testFlag(FileEmbedding::BibTeXFile)) 0058 m_embeddedFileList.append(QString(QStringLiteral("%1|%2|%3")).arg(QStringLiteral("BibTeX source"), m_fileStem + KBibTeX::extensionBibTeX, m_fileBasename + KBibTeX::extensionBibTeX)); 0059 if (m_fileEmbeddings.testFlag(FileEmbedding::References)) 0060 fillEmbeddedFileList(bibtexfile); 0061 0062 QFile output(m_fileStem + KBibTeX::extensionBibTeX); 0063 if (output.open(QIODevice::WriteOnly)) { 0064 FileExporterBibTeX bibtexExporter(this); 0065 bibtexExporter.setEncoding(QStringLiteral("latex")); 0066 result = bibtexExporter.save(&output, bibtexfile); 0067 output.close(); 0068 } 0069 0070 if (result) 0071 result = generatePDF(iodevice); 0072 0073 return result; 0074 } 0075 0076 bool FileExporterPDF::save(QIODevice *iodevice, const QSharedPointer<const Element> &element, const File *bibtexfile) 0077 { 0078 check_if_iodevice_invalid(iodevice); 0079 0080 bool result = false; 0081 m_embeddedFileList.clear(); 0082 //if (m_fileEmbedding & EmbedReferences) 0083 // FIXME need File object fillEmbeddedFileList(element); 0084 0085 QFile output(m_fileStem + KBibTeX::extensionBibTeX); 0086 if (output.open(QIODevice::WriteOnly)) { 0087 FileExporterBibTeX bibtexExporter(this); 0088 bibtexExporter.setEncoding(QStringLiteral("latex")); 0089 result = bibtexExporter.save(&output, element, bibtexfile); 0090 output.close(); 0091 } 0092 0093 if (result) 0094 result = generatePDF(iodevice); 0095 0096 return result; 0097 } 0098 0099 void FileExporterPDF::setDocumentSearchPaths(const QStringList &searchPaths) 0100 { 0101 m_searchPaths = searchPaths; 0102 } 0103 0104 void FileExporterPDF::setFileEmbedding(const FileEmbeddings fileEmbedding) { 0105 /// If there is not embedfile.sty file, disable embedding 0106 /// irrespective of user's wishes 0107 if (!kpsewhich(QStringLiteral("embedfile.sty"))) 0108 m_fileEmbeddings = FileEmbedding::None; 0109 else 0110 m_fileEmbeddings = fileEmbedding; 0111 } 0112 0113 bool FileExporterPDF::generatePDF(QIODevice *iodevice) 0114 { 0115 QStringList cmdLines {QStringLiteral("pdflatex -halt-on-error ") + m_fileStem + KBibTeX::extensionTeX, QStringLiteral("bibtex ") + m_fileStem + KBibTeX::extensionAux, QStringLiteral("pdflatex -halt-on-error ") + m_fileStem + KBibTeX::extensionTeX, QStringLiteral("pdflatex -halt-on-error ") + m_fileStem + KBibTeX::extensionTeX}; 0116 0117 return writeLatexFile(m_fileStem + KBibTeX::extensionTeX) && runProcesses(cmdLines) && writeFileToIODevice(m_fileStem + KBibTeX::extensionPDF, iodevice); 0118 } 0119 0120 bool FileExporterPDF::writeLatexFile(const QString &filename) 0121 { 0122 QFile latexFile(filename); 0123 if (latexFile.open(QIODevice::WriteOnly)) { 0124 QTextStream ts(&latexFile); 0125 // https://forum.qt.io/topic/135724/qt-6-replacement-for-qtextcodec 0126 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0127 ts.setCodec("UTF-8"); 0128 #else 0129 ts.setEncoding(QStringConverter::Utf8); 0130 #endif 0131 #if QT_VERSION >= 0x050e00 0132 ts << "\\documentclass{article}" << Qt::endl; 0133 ts << "\\usepackage[T1]{fontenc}" << Qt::endl; 0134 ts << "\\usepackage[utf8]{inputenc}" << Qt::endl; 0135 #else // QT_VERSION < 0x050e00 0136 ts << "\\documentclass{article}" << endl; 0137 ts << "\\usepackage[T1]{fontenc}" << endl; 0138 ts << "\\usepackage[utf8]{inputenc}" << endl; 0139 #endif // QT_VERSION >= 0x050e00 0140 if (kpsewhich(QStringLiteral("babel.sty"))) 0141 #if QT_VERSION >= 0x050e00 0142 ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}" << Qt::endl; 0143 #else // QT_VERSION < 0x050e00 0144 ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}" << endl; 0145 #endif // QT_VERSION >= 0x050e00 0146 if (kpsewhich(QStringLiteral("hyperref.sty"))) 0147 #if QT_VERSION >= 0x050e00 0148 ts << "\\usepackage[pdfborder={0 0 0},pdfproducer={KBibTeX: https://userbase.kde.org/KBibTeX},pdftex]{hyperref}" << Qt::endl; 0149 #else // QT_VERSION < 0x050e00 0150 ts << "\\usepackage[pdfborder={0 0 0},pdfproducer={KBibTeX: https://userbase.kde.org/KBibTeX},pdftex]{hyperref}" << endl; 0151 #endif // QT_VERSION >= 0x050e00 0152 else if (kpsewhich(QStringLiteral("url.sty"))) 0153 #if QT_VERSION >= 0x050e00 0154 ts << "\\usepackage{url}" << Qt::endl; 0155 #else // QT_VERSION < 0x050e00 0156 ts << "\\usepackage{url}" << endl; 0157 #endif // QT_VERSION >= 0x050e00 0158 const QString bibliographyStyle = Preferences::instance().bibTeXBibliographyStyle(); 0159 if ((bibliographyStyle == QStringLiteral("agsm") || bibliographyStyle == QStringLiteral("dcu") || bibliographyStyle == QStringLiteral("jmr") || bibliographyStyle == QStringLiteral("jphysicsB") || bibliographyStyle == QStringLiteral("kluwer") || bibliographyStyle == QStringLiteral("nederlands") || bibliographyStyle == QStringLiteral("dcu") || bibliographyStyle == QStringLiteral("dcu")) && kpsewhich(QStringLiteral("harvard.sty")) && kpsewhich(QStringLiteral("html.sty"))) 0160 #if QT_VERSION >= 0x050e00 0161 ts << "\\usepackage{html}" << Qt::endl << "\\usepackage[dcucite]{harvard}" << Qt::endl << "\\renewcommand{\\harvardurl}{URL: \\url}" << Qt::endl; 0162 #else // QT_VERSION < 0x050e00 0163 ts << "\\usepackage{html}" << endl << "\\usepackage[dcucite]{harvard}" << endl << "\\renewcommand{\\harvardurl}{URL: \\url}" << endl; 0164 #endif // QT_VERSION >= 0x050e00 0165 if (kpsewhich(QStringLiteral("embedfile.sty"))) 0166 #if QT_VERSION >= 0x050e00 0167 ts << "\\usepackage{embedfile}" << Qt::endl; 0168 #else // QT_VERSION < 0x050e00 0169 ts << "\\usepackage{embedfile}" << endl; 0170 #endif // QT_VERSION >= 0x050e00 0171 if (kpsewhich(QStringLiteral("geometry.sty"))) 0172 #if QT_VERSION >= 0x050e00 0173 ts << "\\usepackage[paper=" << pageSizeToLaTeXName(Preferences::instance().pageSize()) << "]{geometry}" << Qt::endl; 0174 #else // QT_VERSION < 0x050e00 0175 ts << "\\usepackage[paper=" << pageSizeToLaTeXName(Preferences::instance().pageSize()) << "]{geometry}" << endl; 0176 #endif // QT_VERSION >= 0x050e00 0177 #if QT_VERSION >= 0x050e00 0178 ts << "\\bibliographystyle{" << bibliographyStyle << "}" << Qt::endl; 0179 ts << "\\begin{document}" << Qt::endl; 0180 #else // QT_VERSION < 0x050e00 0181 ts << "\\bibliographystyle{" << bibliographyStyle << "}" << endl; 0182 ts << "\\begin{document}" << endl; 0183 #endif // QT_VERSION >= 0x050e00 0184 0185 if (!m_embeddedFileList.isEmpty()) 0186 for (const QString &embeddedFile : const_cast<const QStringList &>(m_embeddedFileList)) { 0187 const QStringList param = embeddedFile.split(QStringLiteral("|")); 0188 QFile file(param[1]); 0189 if (file.exists()) 0190 ts << "\\embedfile[desc={" << param[0] << "}"; 0191 ts << ",filespec={" << param[2] << "}"; 0192 if (param[2].endsWith(KBibTeX::extensionBibTeX)) 0193 ts << ",mimetype={text/x-bibtex}"; 0194 else if (param[2].endsWith(KBibTeX::extensionPDF)) 0195 ts << ",mimetype={application/pdf}"; 0196 #if QT_VERSION >= 0x050e00 0197 ts << "]{" << param[1] << "}" << Qt::endl; 0198 #else // QT_VERSION < 0x050e00 0199 ts << "]{" << param[1] << "}" << endl; 0200 #endif // QT_VERSION >= 0x050e00 0201 } 0202 0203 #if QT_VERSION >= 0x050e00 0204 ts << "\\nocite{*}" << Qt::endl; 0205 ts << QStringLiteral("\\bibliography{") << m_fileBasename << QStringLiteral("}") << Qt::endl; 0206 ts << "\\end{document}" << Qt::endl; 0207 #else // QT_VERSION < 0x050e00 0208 ts << "\\nocite{*}" << endl; 0209 ts << QStringLiteral("\\bibliography{") << m_fileBasename << QStringLiteral("}") << endl; 0210 ts << "\\end{document}" << endl; 0211 #endif // QT_VERSION >= 0x050e00 0212 latexFile.close(); 0213 return true; 0214 } else 0215 return false; 0216 } 0217 0218 void FileExporterPDF::fillEmbeddedFileList(const File *bibtexfile) 0219 { 0220 for (const auto &element : const_cast<const File &>(*bibtexfile)) 0221 fillEmbeddedFileList(element, bibtexfile); 0222 } 0223 0224 void FileExporterPDF::fillEmbeddedFileList(const QSharedPointer<const Element> &element, const File *bibtexfile) 0225 { 0226 if (bibtexfile == nullptr || !bibtexfile->hasProperty(File::Url)) { 0227 /// If no valid File was provided or File is not saved, do not append files 0228 return; 0229 } 0230 0231 const QSharedPointer<const Entry> &entry = element.dynamicCast<const Entry>(); 0232 if (!entry.isNull()) { 0233 const QString title = PlainTextValue::text(entry->value(Entry::ftTitle)); 0234 const auto urlList = FileInfo::entryUrls(entry, bibtexfile->property(File::Url).toUrl(), FileInfo::TestExistence::Yes); 0235 for (const QUrl &url : urlList) { 0236 if (!url.isLocalFile()) continue; 0237 const QString filename = url.toLocalFile(); 0238 const QString basename = QFileInfo(filename).fileName(); 0239 m_embeddedFileList.append(QString(QStringLiteral("%1|%2|%3")).arg(title, filename, basename)); 0240 } 0241 } 0242 }