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 }