diff --git a/src/gui/preferences/settingsfileexporterpdfpswidget.cpp b/src/gui/preferences/settingsfileexporterpdfpswidget.cpp index 8dd02973..7a46cc8e 100644 --- a/src/gui/preferences/settingsfileexporterpdfpswidget.cpp +++ b/src/gui/preferences/settingsfileexporterpdfpswidget.cpp @@ -1,152 +1,140 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "settingsfileexporterpdfpswidget.h" #include #include #include -#include -#include #include #include #include "guihelper.h" #include "fileexportertoolchain.h" #include "preferences.h" class SettingsFileExporterPDFPSWidget::SettingsFileExporterPDFPSWidgetPrivate { private: SettingsFileExporterPDFPSWidget *p; KComboBox *comboBoxPaperSize; KComboBox *comboBoxBabelLanguage; KComboBox *comboBoxBibliographyStyle; - KSharedConfigPtr config; - const QString configGroupName, configGroupNameGeneral ; - public: SettingsFileExporterPDFPSWidgetPrivate(SettingsFileExporterPDFPSWidget *parent) - : p(parent), config(KSharedConfig::openConfig(QStringLiteral("kbibtexrc"))), configGroupName(QStringLiteral("FileExporterPDFPS")), configGroupNameGeneral(QStringLiteral("General")) { - + : p(parent) + { setupGUI(); } void loadState() { - KConfigGroup configGroupGeneral(config, configGroupNameGeneral); - int row = qMax(0, GUIHelper::selectValue(comboBoxPaperSize->model(), static_cast(Preferences::instance().pageSize()), Qt::UserRole)); comboBoxPaperSize->setCurrentIndex(row); - KConfigGroup configGroup(config, configGroupName); - QString babelLanguage = configGroup.readEntry(FileExporterToolchain::keyBabelLanguage, FileExporterToolchain::defaultBabelLanguage); - row = GUIHelper::selectValue(comboBoxBabelLanguage->model(), babelLanguage); + const QString babelLanguage = Preferences::instance().laTeXBabelLanguage(); + row = qMax(0, GUIHelper::selectValue(comboBoxBabelLanguage->model(), babelLanguage)); comboBoxBabelLanguage->setCurrentIndex(row); - QString bibliographyStyle = configGroup.readEntry(FileExporterToolchain::keyBibliographyStyle, FileExporterToolchain::defaultBibliographyStyle); - row = GUIHelper::selectValue(comboBoxBibliographyStyle->model(), bibliographyStyle); + const QString bibliographyStyle = Preferences::instance().bibTeXBibliographyStyle(); + row = qMax(0, GUIHelper::selectValue(comboBoxBibliographyStyle->model(), bibliographyStyle)); comboBoxBibliographyStyle->setCurrentIndex(row); } void saveState() { - KConfigGroup configGroupGeneral(config, configGroupNameGeneral); - Preferences::instance().setPageSize(static_cast(comboBoxPaperSize->currentData().toInt())); - KConfigGroup configGroup(config, configGroupName); - configGroup.writeEntry(FileExporterToolchain::keyBabelLanguage, comboBoxBabelLanguage->lineEdit()->text()); - configGroup.writeEntry(FileExporterToolchain::keyBibliographyStyle, comboBoxBibliographyStyle->lineEdit()->text()); - config->sync(); + Preferences::instance().setLaTeXBabelLanguage(comboBoxBabelLanguage->lineEdit()->text()); + Preferences::instance().setBibTeXBibliographyStyle(comboBoxBibliographyStyle->lineEdit()->text()); } void resetToDefaults() { int row = qMax(0, GUIHelper::selectValue(comboBoxPaperSize->model(), static_cast(Preferences::defaultPageSize), Qt::UserRole)); comboBoxPaperSize->setCurrentIndex(row); - row = GUIHelper::selectValue(comboBoxBabelLanguage->model(), FileExporterToolchain::defaultBabelLanguage); + row = qMax(0, GUIHelper::selectValue(comboBoxBabelLanguage->model(), Preferences::defaultLaTeXBabelLanguage)); comboBoxBabelLanguage->setCurrentIndex(row); - row = GUIHelper::selectValue(comboBoxBibliographyStyle->model(), FileExporterToolchain::defaultBibliographyStyle); + row = qMax(0, GUIHelper::selectValue(comboBoxBibliographyStyle->model(), Preferences::defaultBibTeXBibliographyStyle)); comboBoxBibliographyStyle->setCurrentIndex(row); } void setupGUI() { QFormLayout *layout = new QFormLayout(p); comboBoxPaperSize = new KComboBox(false, p); comboBoxPaperSize->setObjectName(QStringLiteral("comboBoxPaperSize")); layout->addRow(i18n("Paper Size:"), comboBoxPaperSize); for (const auto &dbItem : Preferences::availablePageSizes) comboBoxPaperSize->addItem(QPageSize::name(dbItem.first), dbItem.second); connect(comboBoxPaperSize, static_cast(&QComboBox::currentIndexChanged), p, &SettingsAbstractWidget::changed); comboBoxBabelLanguage = new KComboBox(true, p); comboBoxBabelLanguage->setObjectName(QStringLiteral("comboBoxBabelLanguage")); layout->addRow(i18n("Language for 'babel':"), comboBoxBabelLanguage); comboBoxBabelLanguage->addItem(QStringLiteral("english")); comboBoxBabelLanguage->addItem(QStringLiteral("ngerman")); comboBoxBabelLanguage->addItem(QStringLiteral("swedish")); connect(comboBoxBabelLanguage->lineEdit(), &QLineEdit::textChanged, p, &SettingsFileExporterPDFPSWidget::changed); comboBoxBibliographyStyle = new KComboBox(true, p); comboBoxBibliographyStyle->setObjectName(QStringLiteral("comboBoxBibliographyStyle")); layout->addRow(i18n("Bibliography style:"), comboBoxBibliographyStyle); static const QStringList styles {QString(QStringLiteral("abbrv")), QString(QStringLiteral("alpha")), QString(QStringLiteral("plain")), QString(QStringLiteral("agsm")), QString(QStringLiteral("dcu")), QString(QStringLiteral("jmr")), QString(QStringLiteral("jphysicsB")), QString(QStringLiteral("kluwer")), QString(QStringLiteral("nederlands"))}; for (const QString &style : styles) { comboBoxBibliographyStyle->addItem(style); } connect(comboBoxBibliographyStyle->lineEdit(), &QLineEdit::textChanged, p, &SettingsFileExporterPDFPSWidget::changed); } }; SettingsFileExporterPDFPSWidget::SettingsFileExporterPDFPSWidget(QWidget *parent) : SettingsAbstractWidget(parent), d(new SettingsFileExporterPDFPSWidgetPrivate(this)) { d->loadState(); } SettingsFileExporterPDFPSWidget::~SettingsFileExporterPDFPSWidget() { delete d; } QString SettingsFileExporterPDFPSWidget::label() const { return i18n("PDF & Postscript"); } QIcon SettingsFileExporterPDFPSWidget::icon() const { return QIcon::fromTheme(QStringLiteral("application-pdf")); } void SettingsFileExporterPDFPSWidget::loadState() { d->loadState(); } void SettingsFileExporterPDFPSWidget::saveState() { d->saveState(); } void SettingsFileExporterPDFPSWidget::resetToDefaults() { d->resetToDefaults(); } diff --git a/src/io/fileexporterbibtex2html.cpp b/src/io/fileexporterbibtex2html.cpp index 70cf72b6..f54a1908 100644 --- a/src/io/fileexporterbibtex2html.cpp +++ b/src/io/fileexporterbibtex2html.cpp @@ -1,160 +1,155 @@ /*************************************************************************** - * Copyright (C) 2004-2017 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexporterbibtex2html.h" #include #include #include #include "fileexporterbibtex.h" #include "logging_io.h" class FileExporterBibTeX2HTML::FileExporterBibTeX2HTMLPrivate { private: FileExporterBibTeX2HTML *p; public: QString bibTeXFilename; QString outputFilename; QString bibStyle; FileExporterBibTeX2HTMLPrivate(FileExporterBibTeX2HTML *parent, const QString &workingDir) : p(parent) { bibTeXFilename = QString(workingDir).append("/bibtex-to-html.bib"); outputFilename = QString(workingDir).append("/bibtex-to-html.html"); bibStyle = QStringLiteral("plain"); } bool generateHTML(QIODevice *iodevice, QStringList *errorLog) { if (!checkBSTexists(iodevice)) return false; if (!checkBibTeX2HTMLexists(iodevice)) return false; /// bibtex2html automatically appends ".html" to output filenames QString outputFilenameNoEnding = outputFilename; outputFilenameNoEnding.remove(QStringLiteral(".html")); QStringList args; args << QStringLiteral("-s") << bibStyle; /// BibTeX style (plain, alpha, ...) args << QStringLiteral("-o") << outputFilenameNoEnding; /// redirect the output args << QStringLiteral("-nokeys"); /// do not print the BibTeX keys args << QStringLiteral("-nolinks"); /// do not print any web link args << QStringLiteral("-nodoc"); /// only produces the body of the HTML documents args << QStringLiteral("-nobibsource"); /// do not produce the BibTeX entries file args << QStringLiteral("-debug"); /// verbose mode (to find incorrect BibTeX entries) args << bibTeXFilename; bool result = p->runProcess(QStringLiteral("bibtex2html"), args, errorLog) && p->writeFileToIODevice(outputFilename, iodevice, errorLog); return result; } bool checkBibTeX2HTMLexists(QIODevice *iodevice) { if (!QStandardPaths::findExecutable(QStringLiteral("bibtex2html")).isEmpty()) return true; QTextStream ts(iodevice); ts << QStringLiteral("
"); ts << i18n("The program bibtex2html is not available."); ts << QStringLiteral("
") << endl; ts.flush(); return false; } bool checkBSTexists(QIODevice *iodevice) { if (p->kpsewhich(bibStyle + ".bst")) return true; QTextStream ts(iodevice); ts << QStringLiteral("
"); ts << i18n("The BibTeX style %1 is not available.", bibStyle); ts << QStringLiteral("
") << endl; ts.flush(); return false; } }; FileExporterBibTeX2HTML::FileExporterBibTeX2HTML(QObject *parent) : FileExporterToolchain(parent), d(new FileExporterBibTeX2HTMLPrivate(this, tempDir.path())) { /// nothing } FileExporterBibTeX2HTML::~FileExporterBibTeX2HTML() { delete d; } -void FileExporterBibTeX2HTML::reloadConfig() -{ - /// nothing -} - bool FileExporterBibTeX2HTML::save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(d->bibTeXFilename); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, bibtexfile, errorLog); output.close(); } if (result) result = d->generateHTML(iodevice, errorLog); iodevice->close(); return result; } bool FileExporterBibTeX2HTML::save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(d->bibTeXFilename); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, element, bibtexfile, errorLog); output.close(); } if (result) result = d->generateHTML(iodevice, errorLog); iodevice->close(); return result; } void FileExporterBibTeX2HTML::setLaTeXBibliographyStyle(const QString &bibStyle) { d->bibStyle = bibStyle; } diff --git a/src/io/fileexporterbibtex2html.h b/src/io/fileexporterbibtex2html.h index 40cf64aa..78975633 100644 --- a/src/io/fileexporterbibtex2html.h +++ b/src/io/fileexporterbibtex2html.h @@ -1,45 +1,44 @@ /*************************************************************************** - * Copyright (C) 2004-2017 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ + #ifndef KBIBTEX_IO_FILEEXPORTERBIBTEX2HTML_H #define KBIBTEX_IO_FILEEXPORTERBIBTEX2HTML_H #include "fileexportertoolchain.h" /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterBibTeX2HTML: public FileExporterToolchain { Q_OBJECT public: explicit FileExporterBibTeX2HTML(QObject *parent); ~FileExporterBibTeX2HTML() override; - void reloadConfig() override; - bool save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog = nullptr) override; bool save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog = nullptr) override; void setLaTeXBibliographyStyle(const QString &bibStyle); private: class FileExporterBibTeX2HTMLPrivate; FileExporterBibTeX2HTMLPrivate *d; }; #endif // KBIBTEX_IO_FILEEXPORTERBIBTEX2HTML_H diff --git a/src/io/fileexporterbibtexoutput.cpp b/src/io/fileexporterbibtexoutput.cpp index 348ae974..9cecb7b6 100644 --- a/src/io/fileexporterbibtexoutput.cpp +++ b/src/io/fileexporterbibtexoutput.cpp @@ -1,152 +1,139 @@ /*************************************************************************** - * Copyright (C) 2004-2018 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexporterbibtexoutput.h" #include #include #include #include #include #include #include "element.h" #include "entry.h" #include "fileexporterbibtex.h" #include "kbibtex.h" +#include "preferences.h" #include "logging_io.h" FileExporterBibTeXOutput::FileExporterBibTeXOutput(OutputType outputType, QObject *parent) - : FileExporterToolchain(parent), m_outputType(outputType), m_latexLanguage(QStringLiteral("english")), m_latexBibStyle(QStringLiteral("plain")) + : FileExporterToolchain(parent), m_outputType(outputType) { m_fileBasename = QStringLiteral("bibtex-to-output"); m_fileStem = tempDir.path() + QDir::separator() + m_fileBasename; } FileExporterBibTeXOutput::~FileExporterBibTeXOutput() { /// nothing } -void FileExporterBibTeXOutput::reloadConfig() -{ - /// nothing -} - bool FileExporterBibTeXOutput::save(QIODevice *ioDevice, const File *bibtexfile, QStringList *errorLog) { if (!ioDevice->isWritable() && !ioDevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile bibTeXFile(m_fileStem + KBibTeX::extensionBibTeX); if (bibTeXFile.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("utf-8")); result = bibtexExporter.save(&bibTeXFile, bibtexfile, errorLog); bibTeXFile.close(); } if (result) result = generateOutput(errorLog); if (result) result = writeFileToIODevice(m_fileStem + (m_outputType == BibTeXLogFile ? KBibTeX::extensionBLG : KBibTeX::extensionBBL), ioDevice, errorLog); ioDevice->close(); return result; } bool FileExporterBibTeXOutput::save(QIODevice *ioDevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog) { if (!ioDevice->isWritable() && !ioDevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile bibTeXFile(m_fileStem + KBibTeX::extensionBibTeX); if (bibTeXFile.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("utf-8")); result = bibtexExporter.save(&bibTeXFile, element, bibtexfile, errorLog); bibTeXFile.close(); } if (result) result = generateOutput(errorLog); if (result) result = writeFileToIODevice(m_fileStem + (m_outputType == BibTeXLogFile ? KBibTeX::extensionBLG : KBibTeX::extensionBBL), ioDevice, errorLog); ioDevice->close(); return result; } -void FileExporterBibTeXOutput::setLaTeXLanguage(const QString &language) -{ - m_latexLanguage = language; -} - -void FileExporterBibTeXOutput::setLaTeXBibliographyStyle(const QString &bibStyle) -{ - m_latexBibStyle = bibStyle; -} - bool FileExporterBibTeXOutput::generateOutput(QStringList *errorLog) { QStringList cmdLines {QStringLiteral("pdflatex -halt-on-error ") + m_fileBasename + KBibTeX::extensionTeX, QStringLiteral("bibtex ") + m_fileBasename + KBibTeX::extensionAux}; if (writeLatexFile(m_fileStem + KBibTeX::extensionTeX) && runProcesses(cmdLines, errorLog)) return true; else { qCWarning(LOG_KBIBTEX_IO) << "Generating BibTeX output failed"; return false; } } bool FileExporterBibTeXOutput::writeLatexFile(const QString &filename) { QFile latexFile(filename); if (latexFile.open(QIODevice::WriteOnly)) { QTextStream ts(&latexFile); ts.setCodec("UTF-8"); ts << "\\documentclass{article}\n"; ts << "\\usepackage[T1]{fontenc}\n"; ts << "\\usepackage[utf8]{inputenc}\n"; if (kpsewhich(QStringLiteral("babel.sty"))) - ts << "\\usepackage[" << m_latexLanguage << "]{babel}\n"; + ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}\n"; if (kpsewhich(QStringLiteral("hyperref.sty"))) ts << "\\usepackage[pdfproducer={KBibTeX: https://userbase.kde.org/KBibTeX},pdftex]{hyperref}\n"; else if (kpsewhich(QStringLiteral("url.sty"))) ts << "\\usepackage{url}\n"; - if (m_latexBibStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) + const QString latexBibStyle = Preferences::instance().bibTeXBibliographyStyle(); + if (latexBibStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) ts << "\\usepackage[bibnewpage]{apacite}\n"; - ts << "\\bibliographystyle{" << m_latexBibStyle << "}\n"; + ts << "\\bibliographystyle{" << latexBibStyle << "}\n"; ts << "\\begin{document}\n"; ts << "\\nocite{*}\n"; ts << QStringLiteral("\\bibliography{") + m_fileBasename + QStringLiteral("}\n"); ts << "\\end{document}\n"; latexFile.close(); return true; } else return false; } diff --git a/src/io/fileexporterbibtexoutput.h b/src/io/fileexporterbibtexoutput.h index c90d9bca..4403cd11 100644 --- a/src/io/fileexporterbibtexoutput.h +++ b/src/io/fileexporterbibtexoutput.h @@ -1,55 +1,49 @@ /*************************************************************************** - * Copyright (C) 2004-2017 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ + #ifndef BIBTEXFILEEXPORTERBIBTEXOUTPUT_H #define BIBTEXFILEEXPORTERBIBTEXOUTPUT_H #include #include "fileexportertoolchain.h" /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterBibTeXOutput : public FileExporterToolchain { Q_OBJECT public: enum OutputType {BibTeXLogFile, BibTeXBlockList}; explicit FileExporterBibTeXOutput(OutputType outputType, QObject *parent); ~FileExporterBibTeXOutput() override; - void reloadConfig() override; - bool save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog = nullptr) override; bool save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog = nullptr) override; - void setLaTeXLanguage(const QString &language); - void setLaTeXBibliographyStyle(const QString &bibStyle); - private: OutputType m_outputType; QString m_fileBasename; QString m_fileStem; - QString m_latexLanguage; - QString m_latexBibStyle; bool generateOutput(QStringList *errorLog); bool writeLatexFile(const QString &filename); }; #endif diff --git a/src/io/fileexporterpdf.cpp b/src/io/fileexporterpdf.cpp index 9092a779..f916bff7 100644 --- a/src/io/fileexporterpdf.cpp +++ b/src/io/fileexporterpdf.cpp @@ -1,211 +1,202 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexporterpdf.h" #include #include #include #include #include #include "fileinfo.h" #include "element.h" #include "entry.h" #include "fileexporterbibtex.h" #include "kbibtex.h" #include "preferences.h" #include "logging_io.h" FileExporterPDF::FileExporterPDF(QObject *parent) : FileExporterToolchain(parent) { m_fileBasename = QStringLiteral("bibtex-to-pdf"); m_fileStem = tempDir.path() + QDir::separator() + m_fileBasename; setFileEmbedding(FileExporterPDF::EmbedBibTeXFileAndReferences); - - reloadConfig(); } FileExporterPDF::~FileExporterPDF() { /// nothing } -void FileExporterPDF::reloadConfig() -{ - KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kbibtexrc")); - KConfigGroup configGroup(config, QStringLiteral("FileExporterPDFPS")); - m_babelLanguage = configGroup.readEntry(keyBabelLanguage, defaultBabelLanguage); - m_bibliographyStyle = configGroup.readEntry(keyBibliographyStyle, defaultBibliographyStyle); -} - bool FileExporterPDF::save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; m_embeddedFileList.clear(); if (m_fileEmbedding & EmbedBibTeXFile) m_embeddedFileList.append(QString(QStringLiteral("%1|%2|%3")).arg(QStringLiteral("BibTeX source"), m_fileStem + KBibTeX::extensionBibTeX, m_fileBasename + KBibTeX::extensionBibTeX)); if (m_fileEmbedding & EmbedReferences) fillEmbeddedFileList(bibtexfile); QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, bibtexfile, errorLog); output.close(); } if (result) result = generatePDF(iodevice, errorLog); if (errorLog != nullptr) qCDebug(LOG_KBIBTEX_IO) << "errorLog" << errorLog->join(QStringLiteral(";")); iodevice->close(); return result; } bool FileExporterPDF::save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; m_embeddedFileList.clear(); //if (m_fileEmbedding & EmbedReferences) // FIXME need File object fillEmbeddedFileList(element); QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, element, bibtexfile, errorLog); output.close(); } if (result) result = generatePDF(iodevice, errorLog); iodevice->close(); return result; } void FileExporterPDF::setDocumentSearchPaths(const QStringList &searchPaths) { m_searchPaths = searchPaths; } void FileExporterPDF::setFileEmbedding(FileEmbedding fileEmbedding) { /// If there is not embedfile.sty file, disable embedding /// irrespective of user's wishes if (!kpsewhich(QStringLiteral("embedfile.sty"))) m_fileEmbedding = NoFileEmbedding; else m_fileEmbedding = fileEmbedding; } bool FileExporterPDF::generatePDF(QIODevice *iodevice, QStringList *errorLog) { 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}; return writeLatexFile(m_fileStem + KBibTeX::extensionTeX) && runProcesses(cmdLines, errorLog) && writeFileToIODevice(m_fileStem + KBibTeX::extensionPDF, iodevice, errorLog); } bool FileExporterPDF::writeLatexFile(const QString &filename) { QFile latexFile(filename); if (latexFile.open(QIODevice::WriteOnly)) { QTextStream ts(&latexFile); ts.setCodec("UTF-8"); ts << "\\documentclass{article}" << endl; ts << "\\usepackage[T1]{fontenc}" << endl; ts << "\\usepackage[utf8]{inputenc}" << endl; if (kpsewhich(QStringLiteral("babel.sty"))) - ts << "\\usepackage[" << m_babelLanguage << "]{babel}" << endl; + ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}" << endl; if (kpsewhich(QStringLiteral("hyperref.sty"))) ts << "\\usepackage[pdfborder={0 0 0},pdfproducer={KBibTeX: https://userbase.kde.org/KBibTeX},pdftex]{hyperref}" << endl; else if (kpsewhich(QStringLiteral("url.sty"))) ts << "\\usepackage{url}" << endl; - if (m_bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) + const QString bibliographyStyle = Preferences::instance().bibTeXBibliographyStyle(); + if (bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) ts << "\\usepackage[bibnewpage]{apacite}" << endl; - if ((m_bibliographyStyle == QStringLiteral("agsm") || m_bibliographyStyle == QStringLiteral("dcu") || m_bibliographyStyle == QStringLiteral("jmr") || m_bibliographyStyle == QStringLiteral("jphysicsB") || m_bibliographyStyle == QStringLiteral("kluwer") || m_bibliographyStyle == QStringLiteral("nederlands") || m_bibliographyStyle == QStringLiteral("dcu") || m_bibliographyStyle == QStringLiteral("dcu")) && kpsewhich(QStringLiteral("harvard.sty")) && kpsewhich(QStringLiteral("html.sty"))) + 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"))) ts << "\\usepackage{html}" << endl << "\\usepackage[dcucite]{harvard}" << endl << "\\renewcommand{\\harvardurl}{URL: \\url}" << endl; if (kpsewhich(QStringLiteral("embedfile.sty"))) ts << "\\usepackage{embedfile}" << endl; if (kpsewhich(QStringLiteral("geometry.sty"))) ts << "\\usepackage[paper=" << pageSizeToLaTeXName(Preferences::instance().pageSize()) << "]{geometry}" << endl; - ts << "\\bibliographystyle{" << m_bibliographyStyle << "}" << endl; + ts << "\\bibliographystyle{" << bibliographyStyle << "}" << endl; ts << "\\begin{document}" << endl; if (!m_embeddedFileList.isEmpty()) for (const QString &embeddedFile : const_cast(m_embeddedFileList)) { const QStringList param = embeddedFile.split(QStringLiteral("|")); QFile file(param[1]); if (file.exists()) ts << "\\embedfile[desc={" << param[0] << "}"; ts << ",filespec={" << param[2] << "}"; if (param[2].endsWith(KBibTeX::extensionBibTeX)) ts << ",mimetype={text/x-bibtex}"; else if (param[2].endsWith(KBibTeX::extensionPDF)) ts << ",mimetype={application/pdf}"; ts << "]{" << param[1] << "}" << endl; } ts << "\\nocite{*}" << endl; ts << QStringLiteral("\\bibliography{") << m_fileBasename << QStringLiteral("}") << endl; ts << "\\end{document}" << endl; latexFile.close(); return true; } else return false; } void FileExporterPDF::fillEmbeddedFileList(const File *bibtexfile) { for (const auto &element : const_cast(*bibtexfile)) fillEmbeddedFileList(element, bibtexfile); } void FileExporterPDF::fillEmbeddedFileList(const QSharedPointer element, const File *bibtexfile) { if (bibtexfile == nullptr || !bibtexfile->hasProperty(File::Url)) { /// If no valid File was provided or File is not saved, do not append files return; } const QSharedPointer entry = element.dynamicCast(); if (!entry.isNull()) { const QString title = PlainTextValue::text(entry->value(Entry::ftTitle)); const auto urlList = FileInfo::entryUrls(entry, bibtexfile->property(File::Url).toUrl(), FileInfo::TestExistenceYes); for (const QUrl &url : urlList) { if (!url.isLocalFile()) continue; const QString filename = url.toLocalFile(); const QString basename = QFileInfo(filename).fileName(); m_embeddedFileList.append(QString(QStringLiteral("%1|%2|%3")).arg(title, filename, basename)); } } } diff --git a/src/io/fileexporterpdf.h b/src/io/fileexporterpdf.h index 9ead36e1..ce5ffa11 100644 --- a/src/io/fileexporterpdf.h +++ b/src/io/fileexporterpdf.h @@ -1,60 +1,56 @@ /*************************************************************************** - * Copyright (C) 2004-2017 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ + #ifndef BIBTEXFILEEXPORTERPDF_H #define BIBTEXFILEEXPORTERPDF_H #include #include "fileexportertoolchain.h" /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterPDF : public FileExporterToolchain { Q_OBJECT public: enum FileEmbedding { NoFileEmbedding = 0, EmbedBibTeXFile = 1, EmbedReferences = 2, EmbedBibTeXFileAndReferences = EmbedBibTeXFile | EmbedReferences}; explicit FileExporterPDF(QObject *parent); ~FileExporterPDF() override; - void reloadConfig() override; - bool save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog = nullptr) override; bool save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog = nullptr) override; void setDocumentSearchPaths(const QStringList &searchPaths); void setFileEmbedding(FileEmbedding fileEmbedding); private: QString m_fileBasename; QString m_fileStem; - QString m_babelLanguage; - QString m_paperSize; - QString m_bibliographyStyle; FileEmbedding m_fileEmbedding; QStringList m_embeddedFileList; QStringList m_searchPaths; bool generatePDF(QIODevice *iodevice, QStringList *errorLog); bool writeLatexFile(const QString &filename); void fillEmbeddedFileList(const File *bibtexfile); void fillEmbeddedFileList(const QSharedPointer element, const File *bibtexfile); }; #endif diff --git a/src/io/fileexporterps.cpp b/src/io/fileexporterps.cpp index 2fbd551b..587287dd 100644 --- a/src/io/fileexporterps.cpp +++ b/src/io/fileexporterps.cpp @@ -1,170 +1,158 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexporterps.h" #include #include #include #include -#include -#include - #include "element.h" #include "fileexporterbibtex.h" #include "kbibtex.h" #include "preferences.h" #include "logging_io.h" FileExporterPS::FileExporterPS(QObject *parent) : FileExporterToolchain(parent) { m_fileBasename = QStringLiteral("bibtex-to-ps"); m_fileStem = tempDir.path() + QDir::separator() + m_fileBasename; - - reloadConfig(); } FileExporterPS::~FileExporterPS() { /// nothing } -void FileExporterPS::reloadConfig() -{ - KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kbibtexrc")); - KConfigGroup configGroup(config, QStringLiteral("FileExporterPDFPS")); - m_babelLanguage = configGroup.readEntry(keyBabelLanguage, defaultBabelLanguage); - m_bibliographyStyle = configGroup.readEntry(keyBibliographyStyle, defaultBibliographyStyle); -} - bool FileExporterPS::save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, bibtexfile, errorLog); output.close(); } if (result) result = generatePS(iodevice, errorLog); iodevice->close(); return result; } bool FileExporterPS::save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, element, bibtexfile, errorLog); output.close(); } if (result) result = generatePS(iodevice, errorLog); iodevice->close(); return result; } bool FileExporterPS::generatePS(QIODevice *iodevice, QStringList *errorLog) { QStringList cmdLines {QStringLiteral("latex -halt-on-error bibtex-to-ps.tex"), QStringLiteral("bibtex bibtex-to-ps"), QStringLiteral("latex -halt-on-error bibtex-to-ps.tex"), QStringLiteral("latex -halt-on-error bibtex-to-ps.tex"), QStringLiteral("dvips -R2 -o bibtex-to-ps.ps bibtex-to-ps.dvi")}; return writeLatexFile(m_fileStem + KBibTeX::extensionTeX) && runProcesses(cmdLines, errorLog) && beautifyPostscriptFile(m_fileStem + KBibTeX::extensionPostScript, QStringLiteral("Exported Bibliography")) && writeFileToIODevice(m_fileStem + KBibTeX::extensionPostScript, iodevice, errorLog); } bool FileExporterPS::writeLatexFile(const QString &filename) { QFile latexFile(filename); if (latexFile.open(QIODevice::WriteOnly)) { QTextStream ts(&latexFile); ts.setCodec("UTF-8"); ts << "\\documentclass{article}" << endl; ts << "\\usepackage[T1]{fontenc}" << endl; ts << "\\usepackage[utf8]{inputenc}" << endl; if (kpsewhich(QStringLiteral("babel.sty"))) - ts << "\\usepackage[" << m_babelLanguage << "]{babel}" << endl; + ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}" << endl; if (kpsewhich(QStringLiteral("url.sty"))) ts << "\\usepackage{url}" << endl; - if (m_bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) + const QString bibliographyStyle = Preferences::instance().bibTeXBibliographyStyle(); + if (bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) ts << "\\usepackage[bibnewpage]{apacite}" << endl; - if ((m_bibliographyStyle == QStringLiteral("agsm") || m_bibliographyStyle == QStringLiteral("dcu") || m_bibliographyStyle == QStringLiteral("jmr") || m_bibliographyStyle == QStringLiteral("jphysicsB") || m_bibliographyStyle == QStringLiteral("kluwer") || m_bibliographyStyle == QStringLiteral("nederlands") || m_bibliographyStyle == QStringLiteral("dcu") || m_bibliographyStyle == QStringLiteral("dcu")) && kpsewhich(QStringLiteral("harvard.sty")) && kpsewhich(QStringLiteral("html.sty"))) + 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"))) ts << "\\usepackage{html}" << endl << "\\usepackage[dcucite]{harvard}" << endl << "\\renewcommand{\\harvardurl}{URL: \\url}" << endl; if (kpsewhich(QStringLiteral("geometry.sty"))) ts << "\\usepackage[paper=" << pageSizeToLaTeXName(Preferences::instance().pageSize()) << "]{geometry}" << endl; - ts << "\\bibliographystyle{" << m_bibliographyStyle << "}" << endl; + ts << "\\bibliographystyle{" << bibliographyStyle << "}" << endl; ts << "\\begin{document}" << endl; ts << "\\nocite{*}" << endl; ts << "\\bibliography{bibtex-to-ps}" << endl; ts << "\\end{document}" << endl; latexFile.close(); return true; } else return false; } bool FileExporterPS::beautifyPostscriptFile(const QString &filename, const QString &title) { QFile postscriptFile(filename); if (postscriptFile.open(QFile::ReadOnly)) { QTextStream ts(&postscriptFile); QStringList lines; QString line; int i = 0; while (!(line = ts.readLine()).isNull()) { if (i < 32 && line.startsWith(QStringLiteral("%%Title:"))) line = "%%Title: " + title; else if (i < 32 && line.startsWith(QStringLiteral("%%Creator:"))) line += QStringLiteral("; exported from within KBibTeX: https://userbase.kde.org/KBibTeX"); lines += line; ++i; } postscriptFile.close(); if (postscriptFile.open(QFile::WriteOnly)) { QTextStream ts(&postscriptFile); for (const QString &line : const_cast(lines)) ts << line << endl; postscriptFile.close(); } else return false; } else return false; return true; } diff --git a/src/io/fileexporterps.h b/src/io/fileexporterps.h index c97389ec..784a9c0a 100644 --- a/src/io/fileexporterps.h +++ b/src/io/fileexporterps.h @@ -1,53 +1,49 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #ifndef BIBTEXFILEEXPORTERPS_H #define BIBTEXFILEEXPORTERPS_H #include "fileexportertoolchain.h" class QStringList; /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterPS : public FileExporterToolchain { Q_OBJECT public: explicit FileExporterPS(QObject *parent); ~FileExporterPS() override; - void reloadConfig() override; - bool save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog = nullptr) override; bool save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog = nullptr) override; private: QString m_fileBasename; QString m_fileStem; - QString m_babelLanguage; - QString m_bibliographyStyle; bool generatePS(QIODevice *iodevice, QStringList *errorLog); bool writeLatexFile(const QString &filename); bool beautifyPostscriptFile(const QString &filename, const QString &title); }; #endif diff --git a/src/io/fileexporterrtf.cpp b/src/io/fileexporterrtf.cpp index 450046c1..e97046c8 100644 --- a/src/io/fileexporterrtf.cpp +++ b/src/io/fileexporterrtf.cpp @@ -1,140 +1,128 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexporterrtf.h" #include #include #include #include -#include -#include - #include "element.h" #include "fileexporterbibtex.h" #include "kbibtex.h" #include "preferences.h" #include "logging_io.h" FileExporterRTF::FileExporterRTF(QObject *parent) : FileExporterToolchain(parent) { m_fileBasename = QStringLiteral("bibtex-to-rtf"); m_fileStem = tempDir.path() + QDir::separator() + m_fileBasename; - - reloadConfig(); } FileExporterRTF::~FileExporterRTF() { /// nothing } -void FileExporterRTF::reloadConfig() -{ - KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kbibtexrc")); - KConfigGroup configGroup(config, QStringLiteral("FileExporterPDFPS")); - m_babelLanguage = configGroup.readEntry(keyBabelLanguage, defaultBabelLanguage); - m_bibliographyStyle = configGroup.readEntry(keyBibliographyStyle, defaultBibliographyStyle); -} - bool FileExporterRTF::save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, bibtexfile, errorLog); output.close(); } if (result) result = generateRTF(iodevice, errorLog); iodevice->close(); return result; } bool FileExporterRTF::save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog) { if (!iodevice->isWritable() && !iodevice->open(QIODevice::WriteOnly)) { qCWarning(LOG_KBIBTEX_IO) << "Output device not writable"; return false; } bool result = false; QFile output(m_fileStem + KBibTeX::extensionBibTeX); if (output.open(QIODevice::WriteOnly)) { FileExporterBibTeX bibtexExporter(this); bibtexExporter.setEncoding(QStringLiteral("latex")); result = bibtexExporter.save(&output, element, bibtexfile, errorLog); output.close(); } if (result) result = generateRTF(iodevice, errorLog); iodevice->close(); return result; } bool FileExporterRTF::generateRTF(QIODevice *iodevice, QStringList *errorLog) { - QStringList cmdLines {QStringLiteral("latex -halt-on-error bibtex-to-rtf.tex"), QStringLiteral("bibtex bibtex-to-rtf"), QStringLiteral("latex -halt-on-error bibtex-to-rtf.tex"), QString(QStringLiteral("latex2rtf -i %1 bibtex-to-rtf.tex")).arg(m_babelLanguage)}; + QStringList cmdLines {QStringLiteral("latex -halt-on-error bibtex-to-rtf.tex"), QStringLiteral("bibtex bibtex-to-rtf"), QStringLiteral("latex -halt-on-error bibtex-to-rtf.tex"), QString(QStringLiteral("latex2rtf -i %1 bibtex-to-rtf.tex")).arg(Preferences::instance().laTeXBabelLanguage())}; return writeLatexFile(m_fileStem + KBibTeX::extensionTeX) && runProcesses(cmdLines, errorLog) && writeFileToIODevice(m_fileStem + KBibTeX::extensionRTF, iodevice, errorLog); } bool FileExporterRTF::writeLatexFile(const QString &filename) { QFile latexFile(filename); if (latexFile.open(QIODevice::WriteOnly)) { QTextStream ts(&latexFile); ts.setCodec("UTF-8"); ts << "\\documentclass{article}" << endl; ts << "\\usepackage[T1]{fontenc}" << endl; ts << "\\usepackage[utf8]{inputenc}" << endl; if (kpsewhich(QStringLiteral("babel.sty"))) - ts << "\\usepackage[" << m_babelLanguage << "]{babel}" << endl; + ts << "\\usepackage[" << Preferences::instance().laTeXBabelLanguage() << "]{babel}" << endl; if (kpsewhich(QStringLiteral("url.sty"))) ts << "\\usepackage{url}" << endl; - if (m_bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) + const QString bibliographyStyle = Preferences::instance().bibTeXBibliographyStyle(); + if (bibliographyStyle.startsWith(QStringLiteral("apacite")) && kpsewhich(QStringLiteral("apacite.sty"))) ts << "\\usepackage[bibnewpage]{apacite}" << endl; - if (m_bibliographyStyle == QStringLiteral("dcu") && kpsewhich(QStringLiteral("harvard.sty")) && kpsewhich(QStringLiteral("html.sty"))) + if (bibliographyStyle == QStringLiteral("dcu") && kpsewhich(QStringLiteral("harvard.sty")) && kpsewhich(QStringLiteral("html.sty"))) ts << "\\usepackage{html}" << endl << "\\usepackage[dcucite]{harvard}" << endl << "\\renewcommand{\\harvardurl}{URL: \\url}" << endl; if (kpsewhich(QStringLiteral("geometry.sty"))) ts << "\\usepackage[paper=" << pageSizeToLaTeXName(Preferences::instance().pageSize()) << "]{geometry}" << endl; - ts << "\\bibliographystyle{" << m_bibliographyStyle << "}" << endl; + ts << "\\bibliographystyle{" << bibliographyStyle << "}" << endl; ts << "\\begin{document}" << endl; ts << "\\nocite{*}" << endl; ts << "\\bibliography{bibtex-to-rtf}" << endl; ts << "\\end{document}" << endl; latexFile.close(); return true; } return false; } diff --git a/src/io/fileexporterrtf.h b/src/io/fileexporterrtf.h index 88ac3f02..a2647be2 100644 --- a/src/io/fileexporterrtf.h +++ b/src/io/fileexporterrtf.h @@ -1,51 +1,47 @@ /*************************************************************************** - * Copyright (C) 2004-2017 by Thomas Fischer * + * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ + #ifndef BIBTEXFILEEXPORTERRTF_H #define BIBTEXFILEEXPORTERRTF_H #include "fileexportertoolchain.h" class QTextStream; /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterRTF : public FileExporterToolchain { Q_OBJECT public: explicit FileExporterRTF(QObject *parent); ~FileExporterRTF() override; - void reloadConfig() override; - bool save(QIODevice *iodevice, const File *bibtexfile, QStringList *errorLog = nullptr) override; bool save(QIODevice *iodevice, const QSharedPointer element, const File *bibtexfile, QStringList *errorLog = nullptr) override; private: QString m_fileBasename; QString m_fileStem; - QString m_babelLanguage; - QString m_bibliographyStyle; - QString m_paperSize; bool generateRTF(QIODevice *iodevice, QStringList *errorLog); bool writeLatexFile(const QString &filename); }; #endif diff --git a/src/io/fileexportertoolchain.cpp b/src/io/fileexportertoolchain.cpp index 4b6e947f..433e231a 100644 --- a/src/io/fileexportertoolchain.cpp +++ b/src/io/fileexportertoolchain.cpp @@ -1,166 +1,161 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "fileexportertoolchain.h" #include #include #include #include #include #include #include #include #include #include #include "preferences.h" -const QString FileExporterToolchain::keyBabelLanguage = QStringLiteral("babelLanguage"); -const QString FileExporterToolchain::defaultBabelLanguage = QStringLiteral("english"); -const QString FileExporterToolchain::keyBibliographyStyle = QStringLiteral("bibliographyStyle"); -const QString FileExporterToolchain::defaultBibliographyStyle = QStringLiteral("plain"); - FileExporterToolchain::FileExporterToolchain(QObject *parent) : FileExporter(parent) { tempDir.setAutoRemove(true); } bool FileExporterToolchain::runProcesses(const QStringList &progs, QStringList *errorLog) { bool result = true; int i = 0; emit progress(0, progs.size()); for (QStringList::ConstIterator it = progs.constBegin(); result && it != progs.constEnd(); ++it) { QCoreApplication::instance()->processEvents(); QStringList args = (*it).split(' '); QString cmd = args.first(); args.erase(args.begin()); result &= runProcess(cmd, args, errorLog); emit progress(i++, progs.size()); } QCoreApplication::instance()->processEvents(); return result; } bool FileExporterToolchain::runProcess(const QString &cmd, const QStringList &args, QStringList *errorLog) { QProcess process(this); QProcessEnvironment processEnvironment = QProcessEnvironment::systemEnvironment(); /// Avoid some paranoid security settings in BibTeX processEnvironment.insert(QStringLiteral("openout_any"), QStringLiteral("r")); /// Make applications use working directory as temporary directory processEnvironment.insert(QStringLiteral("TMPDIR"), tempDir.path()); processEnvironment.insert(QStringLiteral("TEMPDIR"), tempDir.path()); process.setProcessEnvironment(processEnvironment); process.setWorkingDirectory(tempDir.path()); /// Assemble the full command line (program name + arguments) /// for use in log messages and debug output const QString fullCommandLine = cmd + QLatin1Char(' ') + args.join(QStringLiteral(" ")); if (errorLog != nullptr) errorLog->append(i18n("Running command '%1' using working directory '%2'", fullCommandLine, process.workingDirectory())); process.start(cmd, args); if (errorLog != nullptr) { /// Redirect any standard output from process into errorLog connect(&process, &QProcess::readyReadStandardOutput, [errorLog, &process] { QTextStream ts(process.readAllStandardOutput()); while (!ts.atEnd()) errorLog->append(ts.readLine()); }); /// Redirect any standard error from process into errorLog connect(&process, &QProcess::readyReadStandardError, [errorLog, &process] { QTextStream ts(process.readAllStandardError()); while (!ts.atEnd()) errorLog->append(ts.readLine()); }); } bool result = process.waitForStarted(3000); if (!result) { if (errorLog != nullptr) errorLog->append(i18n("Starting command '%1' failed: %2", fullCommandLine, process.errorString())); return false; } if (process.waitForFinished(30000)) result = process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; if (errorLog != nullptr) { if (result) errorLog->append(i18n("Command '%1' succeeded", fullCommandLine)); else errorLog->append(i18n("Command '%1' failed with exit code %2: %3", fullCommandLine, process.exitCode(), process.errorString())); } return result; } bool FileExporterToolchain::writeFileToIODevice(const QString &filename, QIODevice *device, QStringList *errorLog) { QFile file(filename); if (file.open(QIODevice::ReadOnly)) { bool result = true; static const qint64 buffersize = 0x10000; qint64 amount = 0; char buffer[buffersize]; do { result = ((amount = file.read(buffer, buffersize)) > -1) && (device->write(buffer, amount) > -1); } while (result && amount > 0); file.close(); if (errorLog != nullptr) errorLog->append(i18n("Writing to file '%1' succeeded", filename)); return result; } if (errorLog != nullptr) errorLog->append(i18n("Writing to file '%1' failed", filename)); return false; } QString FileExporterToolchain::pageSizeToLaTeXName(const QPageSize::PageSizeId pageSizeId) const { for (const auto &dbItem : Preferences::availablePageSizes) if (dbItem.first == pageSizeId) return dbItem.second; return QPageSize::name(pageSizeId).toLower(); ///< just a wild guess } bool FileExporterToolchain::kpsewhich(const QString &filename) { static QHash kpsewhichMap; if (kpsewhichMap.contains(filename)) return kpsewhichMap.value(filename, false); bool result = false; QProcess kpsewhich; const QStringList param {filename}; kpsewhich.start(QStringLiteral("kpsewhich"), param); if (kpsewhich.waitForStarted(3000) && kpsewhich.waitForFinished(30000)) { const QString standardOut = QString::fromUtf8(kpsewhich.readAllStandardOutput()); result = kpsewhich.exitStatus() == QProcess::NormalExit && kpsewhich.exitCode() == 0 && standardOut.endsWith(QDir::separator() + filename + QChar('\n')); kpsewhichMap.insert(filename, result); } return result; } diff --git a/src/io/fileexportertoolchain.h b/src/io/fileexportertoolchain.h index 18de5b59..e5a5e306 100644 --- a/src/io/fileexportertoolchain.h +++ b/src/io/fileexportertoolchain.h @@ -1,58 +1,50 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #ifndef BIBTEXFILEEXPORTERTOOLCHAIN_H #define BIBTEXFILEEXPORTERTOOLCHAIN_H #include #include #include "fileexporter.h" class QString; /** @author Thomas Fischer */ class KBIBTEXIO_EXPORT FileExporterToolchain : public FileExporter { Q_OBJECT public: - static const QString keyBabelLanguage; - static const QString defaultBabelLanguage; - - static const QString keyBibliographyStyle; - static const QString defaultBibliographyStyle; - explicit FileExporterToolchain(QObject *parent); - virtual void reloadConfig() = 0; - static bool kpsewhich(const QString &filename); protected: QTemporaryDir tempDir; bool runProcesses(const QStringList &progs, QStringList *errorLog = nullptr); bool runProcess(const QString &cmd, const QStringList &args, QStringList *errorLog = nullptr); bool writeFileToIODevice(const QString &filename, QIODevice *device, QStringList *errorLog = nullptr); QString pageSizeToLaTeXName(const QPageSize::PageSizeId pageSizeId) const; }; #endif diff --git a/src/parts/part.cpp b/src/parts/part.cpp index 8a10170c..bb118f43 100644 --- a/src/parts/part.cpp +++ b/src/parts/part.cpp @@ -1,1101 +1,1100 @@ /*************************************************************************** * Copyright (C) 2004-2019 by Thomas Fischer * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ #include "part.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // FIXME deprecated #include #include #include #include #include #include #include #include #include #include #include #include #include #include "file.h" #include "macro.h" #include "preamble.h" #include "comment.h" #include "fileinfo.h" #include "fileexporterbibtexoutput.h" #include "fileimporterbibtex.h" #include "fileexporterbibtex.h" #include "fileimporterris.h" #include "fileimporterbibutils.h" #include "fileexporterris.h" #include "fileexporterbibutils.h" #include "fileimporterpdf.h" #include "fileexporterps.h" #include "fileexporterpdf.h" #include "fileexporterrtf.h" #include "fileexporterbibtex2html.h" #include "fileexporterxml.h" #include "fileexporterxslt.h" #include "models/filemodel.h" #include "filesettingswidget.h" #include "filterbar.h" #include "findduplicatesui.h" #include "lyx.h" #include "preferences.h" #include "settingscolorlabelwidget.h" #include "settingsfileexporterpdfpswidget.h" #include "findpdfui.h" #include "valuelistmodel.h" #include "clipboard.h" #include "idsuggestions.h" #include "fileview.h" #include "browserextension.h" #include "logging_parts.h" static const char RCFileName[] = "kbibtexpartui.rc"; static const int smEntry = 1; static const int smComment = 2; static const int smPreamble = 3; static const int smMacro = 4; class KBibTeXPart::KBibTeXPartPrivate { private: KBibTeXPart *p; /** * Modifies a given URL to become a "backup" filename/URL. * A backup level or 0 or less does not modify the URL. * A backup level of 1 appends a '~' (tilde) to the URL's filename. * A backup level of 2 or more appends '~N', where N is the level. * The provided URL will be modified in the process. It is assumed * that the URL is not yet a "backup URL". */ void constructBackupUrl(const int level, QUrl &url) const { if (level <= 0) /// No modification return; else if (level == 1) /// Simply append '~' to the URL's filename url.setPath(url.path() + QStringLiteral("~")); else /// Append '~' followed by a number to the filename url.setPath(url.path() + QString(QStringLiteral("~%1")).arg(level)); } public: File *bibTeXFile; PartWidget *partWidget; FileModel *model; SortFilterFileModel *sortFilterProxyModel; QSignalMapper *signalMapperNewElement; QAction *editCutAction, *editDeleteAction, *editCopyAction, *editPasteAction, *editCopyReferencesAction, *elementEditAction, *elementViewDocumentAction, *fileSaveAction, *elementFindPDFAction, *entryApplyDefaultFormatString; QMenu *viewDocumentMenu; QSignalMapper *signalMapperViewDocument; QSet signalMapperViewDocumentSenders; bool isSaveAsOperation; LyX *lyx; FindDuplicatesUI *findDuplicatesUI; ColorLabelContextMenu *colorLabelContextMenu; QAction *colorLabelContextMenuAction; QFileSystemWatcher fileSystemWatcher; KBibTeXPartPrivate(QWidget *parentWidget, KBibTeXPart *parent) : p(parent), bibTeXFile(nullptr), model(nullptr), sortFilterProxyModel(nullptr), signalMapperNewElement(new QSignalMapper(parent)), viewDocumentMenu(new QMenu(i18n("View Document"), parent->widget())), signalMapperViewDocument(new QSignalMapper(parent)), isSaveAsOperation(false), fileSystemWatcher(p) { connect(signalMapperViewDocument, static_cast(&QSignalMapper::mapped), p, &KBibTeXPart::elementViewDocumentMenu); connect(&fileSystemWatcher, &QFileSystemWatcher::fileChanged, p, &KBibTeXPart::fileExternallyChange); partWidget = new PartWidget(parentWidget); partWidget->fileView()->setReadOnly(!p->isReadWrite()); connect(partWidget->fileView(), &FileView::modified, p, &KBibTeXPart::setModified); setupActions(); } ~KBibTeXPartPrivate() { delete bibTeXFile; delete model; delete signalMapperNewElement; delete viewDocumentMenu; delete signalMapperViewDocument; delete findDuplicatesUI; } void setupActions() { /// "Save" action fileSaveAction = p->actionCollection()->addAction(KStandardAction::Save); connect(fileSaveAction, &QAction::triggered, p, &KBibTeXPart::documentSave); fileSaveAction->setEnabled(false); QAction *action = p->actionCollection()->addAction(KStandardAction::SaveAs); connect(action, &QAction::triggered, p, &KBibTeXPart::documentSaveAs); /// "Save copy as" action QAction *saveCopyAsAction = new QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save Copy As..."), p); p->actionCollection()->addAction(QStringLiteral("file_save_copy_as"), saveCopyAsAction); connect(saveCopyAsAction, &QAction::triggered, p, &KBibTeXPart::documentSaveCopyAs); /// Filter bar widget QAction *filterWidgetAction = new QAction(i18n("Filter"), p); p->actionCollection()->addAction(QStringLiteral("toolbar_filter_widget"), filterWidgetAction); filterWidgetAction->setIcon(QIcon::fromTheme(QStringLiteral("view-filter"))); p->actionCollection()->setDefaultShortcut(filterWidgetAction, Qt::CTRL + Qt::Key_F); connect(filterWidgetAction, &QAction::triggered, partWidget->filterBar(), static_cast(&QWidget::setFocus)); partWidget->filterBar()->setPlaceholderText(i18n("Filter bibliographic entries (%1)", filterWidgetAction->shortcut().toString())); /// Actions for creating new elements (entries, macros, ...) KActionMenu *newElementAction = new KActionMenu(QIcon::fromTheme(QStringLiteral("address-book-new")), i18n("New element"), p); p->actionCollection()->addAction(QStringLiteral("element_new"), newElementAction); QMenu *newElementMenu = new QMenu(newElementAction->text(), p->widget()); newElementAction->setMenu(newElementMenu); connect(newElementAction, &QAction::triggered, p, &KBibTeXPart::newEntryTriggered); QAction *newEntry = newElementMenu->addAction(QIcon::fromTheme(QStringLiteral("address-book-new")), i18n("New entry")); p->actionCollection()->setDefaultShortcut(newEntry, Qt::CTRL + Qt::SHIFT + Qt::Key_N); connect(newEntry, &QAction::triggered, signalMapperNewElement, static_cast(&QSignalMapper::map)); signalMapperNewElement->setMapping(newEntry, smEntry); QAction *newComment = newElementMenu->addAction(QIcon::fromTheme(QStringLiteral("address-book-new")), i18n("New comment")); connect(newComment, &QAction::triggered, signalMapperNewElement, static_cast(&QSignalMapper::map)); signalMapperNewElement->setMapping(newComment, smComment); QAction *newMacro = newElementMenu->addAction(QIcon::fromTheme(QStringLiteral("address-book-new")), i18n("New macro")); connect(newMacro, &QAction::triggered, signalMapperNewElement, static_cast(&QSignalMapper::map)); signalMapperNewElement->setMapping(newMacro, smMacro); QAction *newPreamble = newElementMenu->addAction(QIcon::fromTheme(QStringLiteral("address-book-new")), i18n("New preamble")); connect(newPreamble, &QAction::triggered, signalMapperNewElement, static_cast(&QSignalMapper::map)); signalMapperNewElement->setMapping(newPreamble, smPreamble); connect(signalMapperNewElement, static_cast(&QSignalMapper::mapped), p, &KBibTeXPart::newElementTriggered); /// Action to edit an element elementEditAction = new QAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Edit Element"), p); p->actionCollection()->addAction(QStringLiteral("element_edit"), elementEditAction); p->actionCollection()->setDefaultShortcut(elementEditAction, Qt::CTRL + Qt::Key_E); connect(elementEditAction, &QAction::triggered, partWidget->fileView(), &FileView::editCurrentElement); /// Action to view the document associated to the current element elementViewDocumentAction = new QAction(QIcon::fromTheme(QStringLiteral("application-pdf")), i18n("View Document"), p); p->actionCollection()->addAction(QStringLiteral("element_viewdocument"), elementViewDocumentAction); p->actionCollection()->setDefaultShortcut(elementViewDocumentAction, Qt::CTRL + Qt::Key_D); connect(elementViewDocumentAction, &QAction::triggered, p, &KBibTeXPart::elementViewDocument); /// Action to find a PDF matching the current element elementFindPDFAction = new QAction(QIcon::fromTheme(QStringLiteral("application-pdf")), i18n("Find PDF..."), p); p->actionCollection()->addAction(QStringLiteral("element_findpdf"), elementFindPDFAction); connect(elementFindPDFAction, &QAction::triggered, p, &KBibTeXPart::elementFindPDF); /// Action to reformat the selected elements' ids entryApplyDefaultFormatString = new QAction(QIcon::fromTheme(QStringLiteral("favorites")), i18n("Format entry ids"), p); p->actionCollection()->addAction(QStringLiteral("entry_applydefaultformatstring"), entryApplyDefaultFormatString); connect(entryApplyDefaultFormatString, &QAction::triggered, p, &KBibTeXPart::applyDefaultFormatString); /// Clipboard object, required for various copy&paste operations Clipboard *clipboard = new Clipboard(partWidget->fileView()); /// Actions to cut and copy selected elements as BibTeX code editCutAction = p->actionCollection()->addAction(KStandardAction::Cut, clipboard, SLOT(cut())); editCopyAction = p->actionCollection()->addAction(KStandardAction::Copy, clipboard, SLOT(copy())); /// Action to copy references, e.g. '\cite{fordfulkerson1959}' editCopyReferencesAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy References"), p); p->actionCollection()->setDefaultShortcut(editCopyReferencesAction, Qt::CTRL + Qt::SHIFT + Qt::Key_C); p->actionCollection()->addAction(QStringLiteral("edit_copy_references"), editCopyReferencesAction); connect(editCopyReferencesAction, &QAction::triggered, clipboard, &Clipboard::copyReferences); /// Action to paste BibTeX code editPasteAction = p->actionCollection()->addAction(KStandardAction::Paste, clipboard, SLOT(paste())); /// Action to delete selected rows/elements editDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-table-delete-row")), i18n("Delete"), p); p->actionCollection()->setDefaultShortcut(editDeleteAction, Qt::Key_Delete); p->actionCollection()->addAction(QStringLiteral("edit_delete"), editDeleteAction); connect(editDeleteAction, &QAction::triggered, partWidget->fileView(), &FileView::selectionDelete); /// Build context menu for central BibTeX file view partWidget->fileView()->setContextMenuPolicy(Qt::ActionsContextMenu); ///< context menu is based on actions partWidget->fileView()->addAction(elementEditAction); partWidget->fileView()->addAction(elementViewDocumentAction); QAction *separator = new QAction(p); separator->setSeparator(true); partWidget->fileView()->addAction(separator); partWidget->fileView()->addAction(editCutAction); partWidget->fileView()->addAction(editCopyAction); partWidget->fileView()->addAction(editCopyReferencesAction); partWidget->fileView()->addAction(editPasteAction); partWidget->fileView()->addAction(editDeleteAction); separator = new QAction(p); separator->setSeparator(true); partWidget->fileView()->addAction(separator); partWidget->fileView()->addAction(elementFindPDFAction); partWidget->fileView()->addAction(entryApplyDefaultFormatString); colorLabelContextMenu = new ColorLabelContextMenu(partWidget->fileView()); colorLabelContextMenuAction = p->actionCollection()->addAction(QStringLiteral("entry_colorlabel"), colorLabelContextMenu->menuAction()); findDuplicatesUI = new FindDuplicatesUI(p, partWidget->fileView()); lyx = new LyX(p, partWidget->fileView()); connect(partWidget->fileView(), &FileView::selectedElementsChanged, p, &KBibTeXPart::updateActions); connect(partWidget->fileView(), &FileView::currentElementChanged, p, &KBibTeXPart::updateActions); } FileImporter *fileImporterFactory(const QUrl &url) { QString ending = url.path().toLower(); const auto pos = ending.lastIndexOf(QStringLiteral(".")); ending = ending.mid(pos + 1); if (ending == QStringLiteral("pdf")) { return new FileImporterPDF(p); } else if (ending == QStringLiteral("ris")) { return new FileImporterRIS(p); } else if (BibUtils::available() && ending == QStringLiteral("isi")) { FileImporterBibUtils *fileImporterBibUtils = new FileImporterBibUtils(p); fileImporterBibUtils->setFormat(BibUtils::ISI); return fileImporterBibUtils; } else { FileImporterBibTeX *fileImporterBibTeX = new FileImporterBibTeX(p); fileImporterBibTeX->setCommentHandling(FileImporterBibTeX::KeepComments); return fileImporterBibTeX; } } FileExporter *fileExporterFactory(const QString &ending) { if (ending == QStringLiteral("html")) { return new FileExporterHTML(p); } else if (ending == QStringLiteral("xml")) { return new FileExporterXML(p); } else if (ending == QStringLiteral("ris")) { return new FileExporterRIS(p); } else if (ending == QStringLiteral("pdf")) { return new FileExporterPDF(p); } else if (ending == QStringLiteral("ps")) { return new FileExporterPS(p); } else if (BibUtils::available() && ending == QStringLiteral("isi")) { FileExporterBibUtils *fileExporterBibUtils = new FileExporterBibUtils(p); fileExporterBibUtils->setFormat(BibUtils::ISI); return fileExporterBibUtils; } else if (ending == QStringLiteral("rtf")) { return new FileExporterRTF(p); } else if (ending == QStringLiteral("html") || ending == QStringLiteral("htm")) { return new FileExporterBibTeX2HTML(p); } else if (ending == QStringLiteral("bbl")) { return new FileExporterBibTeXOutput(FileExporterBibTeXOutput::BibTeXBlockList, p); } else { return new FileExporterBibTeX(p); } } QString findUnusedId() { int i = 1; while (true) { QString result = i18n("New%1", i); if (!bibTeXFile->containsKey(result)) return result; ++i; } return QString(); } void initializeNew() { bibTeXFile = new File(); model = new FileModel(); model->setBibliographyFile(bibTeXFile); if (sortFilterProxyModel != nullptr) delete sortFilterProxyModel; sortFilterProxyModel = new SortFilterFileModel(p); sortFilterProxyModel->setSourceModel(model); partWidget->fileView()->setModel(sortFilterProxyModel); connect(partWidget->filterBar(), &FilterBar::filterChanged, sortFilterProxyModel, &SortFilterFileModel::updateFilter); } bool openFile(const QUrl &url, const QString &localFilePath) { p->setObjectName("KBibTeXPart::KBibTeXPart for " + url.toDisplayString() + " aka " + localFilePath); qApp->setOverrideCursor(Qt::WaitCursor); if (bibTeXFile != nullptr) { const QUrl oldUrl = bibTeXFile->property(File::Url, QUrl()).toUrl(); if (oldUrl.isValid() && oldUrl.isLocalFile()) { const QString path = oldUrl.toLocalFile(); if (!path.isEmpty()) fileSystemWatcher.removePath(path); else qCWarning(LOG_KBIBTEX_PARTS) << "No filename to stop watching"; } delete bibTeXFile; bibTeXFile = nullptr; } QFile inputfile(localFilePath); if (!inputfile.open(QIODevice::ReadOnly)) { qCWarning(LOG_KBIBTEX_PARTS) << "Opening file failed, creating new one instead:" << url.toDisplayString() << "aka" << localFilePath; qApp->restoreOverrideCursor(); /// Opening file failed, creating new one instead initializeNew(); return false; } FileImporter *importer = fileImporterFactory(url); importer->showImportDialog(p->widget()); bibTeXFile = importer->load(&inputfile); inputfile.close(); delete importer; if (bibTeXFile == nullptr) { qCWarning(LOG_KBIBTEX_PARTS) << "Opening file failed, creating new one instead:" << url.toDisplayString() << "aka" << localFilePath; qApp->restoreOverrideCursor(); /// Opening file failed, creating new one instead initializeNew(); return false; } bibTeXFile->setProperty(File::Url, QUrl(url)); model->setBibliographyFile(bibTeXFile); if (sortFilterProxyModel != nullptr) delete sortFilterProxyModel; sortFilterProxyModel = new SortFilterFileModel(p); sortFilterProxyModel->setSourceModel(model); partWidget->fileView()->setModel(sortFilterProxyModel); connect(partWidget->filterBar(), &FilterBar::filterChanged, sortFilterProxyModel, &SortFilterFileModel::updateFilter); if (url.isLocalFile()) fileSystemWatcher.addPath(url.toLocalFile()); qApp->restoreOverrideCursor(); return true; } void makeBackup(const QUrl &url) const { /// Fetch settings from configuration const int numberOfBackups = Preferences::instance().numberOfBackups(); /// Stop right here if no backup is requested if (Preferences::instance().backupScope() == Preferences::NoBackup) return; /// For non-local files, proceed only if backups to remote storage is allowed if (Preferences::instance().backupScope() != Preferences::BothLocalAndRemote && !url.isLocalFile()) return; /// Do not make backup copies if destination file does not exist yet KIO::StatJob *statJob = KIO::stat(url, KIO::StatJob::DestinationSide, 0 /** not details necessary, just need to know if file exists */, KIO::HideProgressInfo); KJobWidgets::setWindow(statJob, p->widget()); statJob->exec(); if (statJob->error() == KIO::ERR_DOES_NOT_EXIST) return; else if (statJob->error() != KIO::Job::NoError) { /// Something else went wrong, quit with error qCWarning(LOG_KBIBTEX_PARTS) << "Probing" << url.toDisplayString() << "failed:" << statJob->errorString(); return; } bool copySucceeded = true; /// Copy e.g. test.bib~ to test.bib~2, test.bib to test.bib~ etc. for (int level = numberOfBackups; copySucceeded && level >= 1; --level) { QUrl newerBackupUrl = url; constructBackupUrl(level - 1, newerBackupUrl); QUrl olderBackupUrl = url; constructBackupUrl(level, olderBackupUrl); statJob = KIO::stat(newerBackupUrl, KIO::StatJob::DestinationSide, 0 /** not details necessary, just need to know if file exists */, KIO::HideProgressInfo); KJobWidgets::setWindow(statJob, p->widget()); if (statJob->exec() && statJob->error() == KIO::Job::NoError) { KIO::CopyJob *moveJob = nullptr; ///< guaranteed to be initialized in either branch of the following code /** * The following 'if' block is necessary to handle the * following situation: User opens, modifies, and saves * file /tmp/b/bbb.bib which is actually a symlink to * file /tmp/a/aaa.bib. Now a 'move' operation like the * implicit 'else' section below does, would move /tmp/b/bbb.bib * to become /tmp/b/bbb.bib~ still pointing to /tmp/a/aaa.bib. * Then, the save operation would create a new file /tmp/b/bbb.bib * without any symbolic linking to /tmp/a/aaa.bib. * The following code therefore checks if /tmp/b/bbb.bib is * to be copied/moved to /tmp/b/bbb.bib~ and /tmp/b/bbb.bib * is a local file and /tmp/b/bbb.bib is a symbolic link to * another file. Then /tmp/b/bbb.bib is resolved to the real * file /tmp/a/aaa.bib which is then copied into plain file * /tmp/b/bbb.bib~. The save function (outside of this function's * scope) will then see that /tmp/b/bbb.bib is a symbolic link, * resolve this symlink to /tmp/a/aaa.bib, and then write * all changes to /tmp/a/aaa.bib keeping /tmp/b/bbb.bib a * link to. */ if (level == 1 && newerBackupUrl.isLocalFile() /** for level==1, this is actually the current file*/) { QFileInfo newerBackupFileInfo(newerBackupUrl.toLocalFile()); if (newerBackupFileInfo.isSymLink()) { while (newerBackupFileInfo.isSymLink()) { newerBackupUrl = QUrl::fromLocalFile(newerBackupFileInfo.symLinkTarget()); newerBackupFileInfo = QFileInfo(newerBackupUrl.toLocalFile()); } moveJob = KIO::copy(newerBackupUrl, olderBackupUrl, KIO::HideProgressInfo | KIO::Overwrite); } } if (moveJob == nullptr) ///< implicit 'else' section, see longer comment above moveJob = KIO::move(newerBackupUrl, olderBackupUrl, KIO::HideProgressInfo | KIO::Overwrite); KJobWidgets::setWindow(moveJob, p->widget()); copySucceeded = moveJob->exec(); } } if (!copySucceeded) KMessageBox::error(p->widget(), i18n("Could not create backup copies of document '%1'.", url.url(QUrl::PreferLocalFile)), i18n("Backup copies")); } QUrl getSaveFilename(bool mustBeImportable = true) { QString startDir = p->url().isValid() ? p->url().path() : QString(); QString supportedMimeTypes = QStringLiteral("text/x-bibtex text/x-research-info-systems"); if (BibUtils::available()) supportedMimeTypes += QStringLiteral(" application/x-isi-export-format application/x-endnote-refer"); if (!mustBeImportable && !QStandardPaths::findExecutable(QStringLiteral("pdflatex")).isEmpty()) supportedMimeTypes += QStringLiteral(" application/pdf"); if (!mustBeImportable && !QStandardPaths::findExecutable(QStringLiteral("dvips")).isEmpty()) supportedMimeTypes += QStringLiteral(" application/postscript"); if (!mustBeImportable) supportedMimeTypes += QStringLiteral(" text/html"); if (!mustBeImportable && !QStandardPaths::findExecutable(QStringLiteral("latex2rtf")).isEmpty()) supportedMimeTypes += QStringLiteral(" application/rtf"); QPointer saveDlg = new QFileDialog(p->widget(), i18n("Save file") /* TODO better text */, startDir, supportedMimeTypes); /// Setting list of mime types for the second time, /// essentially calling this function only to set the "default mime type" parameter saveDlg->setMimeTypeFilters(supportedMimeTypes.split(QLatin1Char(' '), QString::SkipEmptyParts)); /// Setting the dialog into "Saving" mode make the "add extension" checkbox available saveDlg->setAcceptMode(QFileDialog::AcceptSave); saveDlg->setDefaultSuffix(QStringLiteral("bib")); saveDlg->setFileMode(QFileDialog::AnyFile); if (saveDlg->exec() != QDialog::Accepted) /// User cancelled saving operation, return invalid filename/URL return QUrl(); const QList selectedUrls = saveDlg->selectedUrls(); delete saveDlg; return selectedUrls.isEmpty() ? QUrl() : selectedUrls.first(); } FileExporter *saveFileExporter(const QString &ending) { FileExporter *exporter = fileExporterFactory(ending); if (isSaveAsOperation) { /// only show export dialog at SaveAs or SaveCopyAs operations FileExporterToolchain *fet = nullptr; if (FileExporterBibTeX::isFileExporterBibTeX(*exporter)) { QPointer dlg = new QDialog(p->widget()); dlg->setWindowTitle(i18n("BibTeX File Settings")); QBoxLayout *layout = new QVBoxLayout(dlg); FileSettingsWidget *settingsWidget = new FileSettingsWidget(dlg); layout->addWidget(settingsWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Reset | QDialogButtonBox::Ok, Qt::Horizontal, dlg); layout->addWidget(buttonBox); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, settingsWidget, &FileSettingsWidget::resetToDefaults); connect(buttonBox->button(QDialogButtonBox::Reset), &QPushButton::clicked, settingsWidget, &FileSettingsWidget::resetToLoadedProperties); connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, dlg.data(), &QDialog::accept); settingsWidget->loadProperties(bibTeXFile); if (dlg->exec() == QDialog::Accepted) settingsWidget->saveProperties(bibTeXFile); delete dlg; } else if ((fet = qobject_cast(exporter)) != nullptr) { QPointer dlg = new QDialog(p->widget()); dlg->setWindowTitle(i18n("PDF/PostScript File Settings")); QBoxLayout *layout = new QVBoxLayout(dlg); SettingsFileExporterPDFPSWidget *settingsWidget = new SettingsFileExporterPDFPSWidget(dlg); layout->addWidget(settingsWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Reset | QDialogButtonBox::Ok, Qt::Horizontal, dlg); layout->addWidget(buttonBox); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, settingsWidget, &SettingsFileExporterPDFPSWidget::resetToDefaults); connect(buttonBox->button(QDialogButtonBox::Reset), &QPushButton::clicked, settingsWidget, &SettingsFileExporterPDFPSWidget::loadState); connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, dlg.data(), &QDialog::accept); if (dlg->exec() == QDialog::Accepted) settingsWidget->saveState(); - fet->reloadConfig(); delete dlg; } } return exporter; } bool saveFile(QFile &file, FileExporter *exporter, QStringList *errorLog = nullptr) { SortFilterFileModel *model = qobject_cast(partWidget->fileView()->model()); Q_ASSERT_X(model != nullptr, "FileExporter *KBibTeXPart::KBibTeXPartPrivate:saveFile(...)", "SortFilterFileModel *model from editor->model() is invalid"); return exporter->save(&file, model->fileSourceModel()->bibliographyFile(), errorLog); } bool saveFile(const QUrl &url) { bool result = false; Q_ASSERT_X(!url.isEmpty(), "bool KBibTeXPart::KBibTeXPartPrivate:saveFile(const QUrl &url)", "url is not allowed to be empty"); /// Extract filename extension (e.g. 'bib') to determine which FileExporter to use static const QRegularExpression suffixRegExp(QStringLiteral("\\.([^.]{1,4})$")); const QRegularExpressionMatch suffixRegExpMatch = suffixRegExp.match(url.fileName()); const QString ending = suffixRegExpMatch.hasMatch() ? suffixRegExpMatch.captured(1) : QStringLiteral("bib"); FileExporter *exporter = saveFileExporter(ending); /// String list to collect error message from FileExporer QStringList errorLog; qApp->setOverrideCursor(Qt::WaitCursor); if (url.isLocalFile()) { /// Take precautions for local files QFileInfo fileInfo(url.toLocalFile()); /// Do not overwrite symbolic link, but linked file instead QString filename = fileInfo.absoluteFilePath(); while (fileInfo.isSymLink()) { filename = fileInfo.symLinkTarget(); fileInfo = QFileInfo(filename); } if (!fileInfo.exists() || fileInfo.isWritable()) { /// Make backup before overwriting target destination, intentionally /// using the provided filename, not the resolved symlink makeBackup(url); QFile file(filename); if (file.open(QIODevice::WriteOnly)) { result = saveFile(file, exporter, &errorLog); file.close(); } } } else { /// URL points to a remote location /// Configure and open temporary file QTemporaryFile temporaryFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + QStringLiteral("kbibtex_savefile_XXXXXX") + ending); temporaryFile.setAutoRemove(true); if (temporaryFile.open()) { result = saveFile(temporaryFile, exporter, &errorLog); /// Close/flush temporary file temporaryFile.close(); if (result) { /// Make backup before overwriting target destination makeBackup(url); KIO::CopyJob *copyJob = KIO::copy(QUrl::fromLocalFile(temporaryFile.fileName()), url, KIO::HideProgressInfo | KIO::Overwrite); KJobWidgets::setWindow(copyJob, p->widget()); result &= copyJob->exec() && copyJob->error() == KIO::Job::NoError; } } } qApp->restoreOverrideCursor(); delete exporter; if (!result) { QString msg = i18n("Saving the bibliography to file '%1' failed.", url.toDisplayString()); if (errorLog.isEmpty()) KMessageBox::error(p->widget(), msg, i18n("Saving bibliography failed")); else { msg += QLatin1String("\n\n"); msg += i18n("The following output was generated by the export filter:"); KMessageBox::errorList(p->widget(), msg, errorLog, i18n("Saving bibliography failed")); } } return result; } /** * Builds or resets the menu with local and remote * references (URLs, files) of an entry. * * @return Number of known references */ int updateViewDocumentMenu() { viewDocumentMenu->clear(); int result = 0; ///< Initially, no references are known File *bibliographyFile = partWidget != nullptr && partWidget->fileView() != nullptr && partWidget->fileView()->fileModel() != nullptr ? partWidget->fileView()->fileModel()->bibliographyFile() : nullptr; if (bibliographyFile == nullptr) return result; /// Clean signal mapper of old mappings /// as stored in QSet signalMapperViewDocumentSenders /// and identified by their QAction*'s QSet::Iterator it = signalMapperViewDocumentSenders.begin(); while (it != signalMapperViewDocumentSenders.end()) { signalMapperViewDocument->removeMappings(*it); it = signalMapperViewDocumentSenders.erase(it); } /// Retrieve Entry object of currently selected line /// in main list view QSharedPointer entry = partWidget->fileView()->currentElement().dynamicCast(); /// Test and continue if there was an Entry to retrieve if (!entry.isNull()) { /// Get list of URLs associated with this entry const auto urlList = FileInfo::entryUrls(entry, bibliographyFile->property(File::Url).toUrl(), FileInfo::TestExistenceYes); if (!urlList.isEmpty()) { /// Memorize first action, necessary to set menu title QAction *firstAction = nullptr; /// First iteration: local references only for (const QUrl &url : urlList) { /// First iteration: local references only if (!url.isLocalFile()) continue; ///< skip remote URLs /// Build a nice menu item (label, icon, ...) const QFileInfo fi(url.toLocalFile()); const QString label = QString(QStringLiteral("%1 [%2]")).arg(fi.fileName(), fi.absolutePath()); QMimeDatabase db; QAction *action = new QAction(QIcon::fromTheme(db.mimeTypeForUrl(url).iconName()), label, p); action->setData(fi.absoluteFilePath()); action->setToolTip(fi.absoluteFilePath()); /// Register action at signal handler to open URL when triggered connect(action, &QAction::triggered, signalMapperViewDocument, static_cast(&QSignalMapper::map)); signalMapperViewDocument->setMapping(action, action); signalMapperViewDocumentSenders.insert(action); viewDocumentMenu->addAction(action); /// Memorize first action if (firstAction == nullptr) firstAction = action; } if (firstAction != nullptr) { /// If there is 'first action', then there must be /// local URLs (i.e. local files) and firstAction /// is the first one where a title can be set above viewDocumentMenu->insertSection(firstAction, i18n("Local Files")); } firstAction = nullptr; /// Now the first remote action is to be memorized /// Second iteration: remote references only for (const QUrl &url : urlList) { if (url.isLocalFile()) continue; ///< skip local files /// Build a nice menu item (label, icon, ...) const QString prettyUrl = url.toDisplayString(); QMimeDatabase db; QAction *action = new QAction(QIcon::fromTheme(db.mimeTypeForUrl(url).iconName()), prettyUrl, p); action->setData(prettyUrl); action->setToolTip(prettyUrl); /// Register action at signal handler to open URL when triggered connect(action, &QAction::triggered, signalMapperViewDocument, static_cast(&QSignalMapper::map)); signalMapperViewDocument->setMapping(action, action); signalMapperViewDocumentSenders.insert(action); viewDocumentMenu->addAction(action); /// Memorize first action if (firstAction == nullptr) firstAction = action; } if (firstAction != nullptr) { /// If there is 'first action', then there must be /// some remote URLs and firstAction is the first /// one where a title can be set above viewDocumentMenu->insertSection(firstAction, i18n("Remote Files")); } result = urlList.count(); } } return result; } void readConfiguration() { disconnect(partWidget->fileView(), &FileView::elementExecuted, partWidget->fileView(), &FileView::editElement); disconnect(partWidget->fileView(), &FileView::elementExecuted, p, &KBibTeXPart::elementViewDocument); switch (Preferences::instance().fileViewDoubleClickAction()) { case Preferences::ActionOpenEditor: connect(partWidget->fileView(), &FileView::elementExecuted, partWidget->fileView(), &FileView::editElement); break; case Preferences::ActionViewDocument: connect(partWidget->fileView(), &FileView::elementExecuted, p, &KBibTeXPart::elementViewDocument); break; } } }; KBibTeXPart::KBibTeXPart(QWidget *parentWidget, QObject *parent, const KAboutData &componentData) : KParts::ReadWritePart(parent), d(new KBibTeXPartPrivate(parentWidget, this)) { setComponentData(componentData); setWidget(d->partWidget); updateActions(); d->initializeNew(); setXMLFile(RCFileName); new BrowserExtension(this); NotificationHub::registerNotificationListener(this, NotificationHub::EventConfigurationChanged); d->readConfiguration(); setModified(false); } KBibTeXPart::~KBibTeXPart() { delete d; } void KBibTeXPart::setModified(bool modified) { KParts::ReadWritePart::setModified(modified); d->fileSaveAction->setEnabled(modified); } void KBibTeXPart::notificationEvent(int eventId) { if (eventId == NotificationHub::EventConfigurationChanged) d->readConfiguration(); } bool KBibTeXPart::saveFile() { Q_ASSERT_X(isReadWrite(), "bool KBibTeXPart::saveFile()", "Trying to save although document is in read-only mode"); if (url().isEmpty()) return documentSaveAs(); /// If the current file is "watchable" (i.e. a local file), /// memorize local filename for future reference const QString watchableFilename = url().isValid() && url().isLocalFile() ? url().toLocalFile() : QString(); /// Stop watching local file that will be written to if (!watchableFilename.isEmpty()) d->fileSystemWatcher.removePath(watchableFilename); else qCWarning(LOG_KBIBTEX_PARTS) << "watchableFilename is Empty"; const bool saveOperationSuccess = d->saveFile(url()); if (!watchableFilename.isEmpty()) { /// Continue watching a local file after write operation, but do /// so only after a short delay. The delay is necessary in some /// situations as observed in KDE bug report 396343 where the /// DropBox client seemingly touched the file right after saving /// from within KBibTeX, triggering KBibTeX to show a 'reload' /// message box. QTimer::singleShot(500, this, [this, watchableFilename]() { d->fileSystemWatcher.addPath(watchableFilename); }); } else qCWarning(LOG_KBIBTEX_PARTS) << "watchableFilename is Empty"; if (!saveOperationSuccess) { KMessageBox::error(widget(), i18n("The document could not be saved, as it was not possible to write to '%1'.\n\nCheck that you have write access to this file or that enough disk space is available.", url().toDisplayString())); return false; } return true; } bool KBibTeXPart::documentSave() { d->isSaveAsOperation = false; if (!isReadWrite()) return documentSaveCopyAs(); else if (!url().isValid()) return documentSaveAs(); else return KParts::ReadWritePart::save(); } bool KBibTeXPart::documentSaveAs() { d->isSaveAsOperation = true; QUrl newUrl = d->getSaveFilename(); if (!newUrl.isValid()) return false; /// Remove old URL from file system watcher if (url().isValid() && url().isLocalFile()) { const QString path = url().toLocalFile(); if (!path.isEmpty()) d->fileSystemWatcher.removePath(path); else qCWarning(LOG_KBIBTEX_PARTS) << "No filename to stop watching"; } else qCWarning(LOG_KBIBTEX_PARTS) << "Not removing" << url().url(QUrl::PreferLocalFile) << "from fileSystemWatcher"; // TODO how does SaveAs dialog know which mime types to support? if (KParts::ReadWritePart::saveAs(newUrl)) { // FIXME d->model->bibliographyFile()->setProperty(File::Url, newUrl); return true; } else return false; } bool KBibTeXPart::documentSaveCopyAs() { d->isSaveAsOperation = true; QUrl newUrl = d->getSaveFilename(false); if (!newUrl.isValid() || newUrl == url()) return false; /// difference from KParts::ReadWritePart::saveAs: /// current document's URL won't be changed return d->saveFile(newUrl); } void KBibTeXPart::elementViewDocument() { QUrl url; const QList actionList = d->viewDocumentMenu->actions(); /// Go through all actions (i.e. document URLs) for this element for (const QAction *action : actionList) { /// Make URL from action's data ... QUrl tmpUrl = QUrl(action->data().toString()); /// ... but skip this action if the URL is invalid if (!tmpUrl.isValid()) continue; if (tmpUrl.isLocalFile()) { /// If action's URL points to local file, /// keep it and stop search for document url = tmpUrl; break; } else if (!url.isValid()) /// First valid URL found, keep it /// URL is not local, so it may get overwritten by another URL url = tmpUrl; } /// Open selected URL if (url.isValid()) { /// Guess mime type for url to open QMimeType mimeType = FileInfo::mimeTypeForUrl(url); const QString mimeTypeName = mimeType.name(); /// Ask KDE subsystem to open url in viewer matching mime type #if KIO_VERSION < 0x051f00 // < 5.31.0 KRun::runUrl(url, mimeTypeName, widget(), false, false); #else // KIO_VERSION < 0x051f00 // >= 5.31.0 KRun::runUrl(url, mimeTypeName, widget(), KRun::RunFlags()); #endif // KIO_VERSION < 0x051f00 } } void KBibTeXPart::elementViewDocumentMenu(QObject *obj) { QString text = static_cast(obj)->data().toString(); ///< only a QAction will be passed along /// Guess mime type for url to open QUrl url(text); QMimeType mimeType = FileInfo::mimeTypeForUrl(url); const QString mimeTypeName = mimeType.name(); /// Ask KDE subsystem to open url in viewer matching mime type #if KIO_VERSION < 0x051f00 // < 5.31.0 KRun::runUrl(url, mimeTypeName, widget(), false, false); #else // KIO_VERSION < 0x051f00 // >= 5.31.0 KRun::runUrl(url, mimeTypeName, widget(), KRun::RunFlags()); #endif // KIO_VERSION < 0x051f00 } void KBibTeXPart::elementFindPDF() { QModelIndexList mil = d->partWidget->fileView()->selectionModel()->selectedRows(); if (mil.count() == 1) { QSharedPointer entry = d->partWidget->fileView()->fileModel()->element(d->partWidget->fileView()->sortFilterProxyModel()->mapToSource(*mil.constBegin()).row()).dynamicCast(); if (!entry.isNull()) FindPDFUI::interactiveFindPDF(*entry, *d->bibTeXFile, widget()); } } void KBibTeXPart::applyDefaultFormatString() { FileModel *model = d->partWidget != nullptr && d->partWidget->fileView() != nullptr ? d->partWidget->fileView()->fileModel() : nullptr; if (model == nullptr) return; bool documentModified = false; const QModelIndexList mil = d->partWidget->fileView()->selectionModel()->selectedRows(); for (const QModelIndex &index : mil) { QSharedPointer entry = model->element(d->partWidget->fileView()->sortFilterProxyModel()->mapToSource(index).row()).dynamicCast(); if (!entry.isNull()) { static IdSuggestions idSuggestions; bool success = idSuggestions.applyDefaultFormatId(*entry.data()); documentModified |= success; if (!success) { KMessageBox::information(widget(), i18n("Cannot apply default formatting for entry ids: No default format specified."), i18n("Cannot Apply Default Formatting")); break; } } } if (documentModified) d->partWidget->fileView()->externalModification(); } bool KBibTeXPart::openFile() { const bool success = d->openFile(url(), localFilePath()); emit completed(); return success; } void KBibTeXPart::newElementTriggered(int event) { switch (event) { case smComment: newCommentTriggered(); break; case smMacro: newMacroTriggered(); break; case smPreamble: newPreambleTriggered(); break; default: newEntryTriggered(); } } void KBibTeXPart::newEntryTriggered() { QSharedPointer newEntry = QSharedPointer(new Entry(QStringLiteral("Article"), d->findUnusedId())); d->model->insertRow(newEntry, d->model->rowCount()); d->partWidget->fileView()->setSelectedElement(newEntry); if (d->partWidget->fileView()->editElement(newEntry)) d->partWidget->fileView()->scrollToBottom(); // FIXME always correct behaviour? else { /// Editing this new element was cancelled, /// therefore remove it again d->model->removeRow(d->model->rowCount() - 1); } } void KBibTeXPart::newMacroTriggered() { QSharedPointer newMacro = QSharedPointer(new Macro(d->findUnusedId())); d->model->insertRow(newMacro, d->model->rowCount()); d->partWidget->fileView()->setSelectedElement(newMacro); if (d->partWidget->fileView()->editElement(newMacro)) d->partWidget->fileView()->scrollToBottom(); // FIXME always correct behaviour? else { /// Editing this new element was cancelled, /// therefore remove it again d->model->removeRow(d->model->rowCount() - 1); } } void KBibTeXPart::newPreambleTriggered() { QSharedPointer newPreamble = QSharedPointer(new Preamble()); d->model->insertRow(newPreamble, d->model->rowCount()); d->partWidget->fileView()->setSelectedElement(newPreamble); if (d->partWidget->fileView()->editElement(newPreamble)) d->partWidget->fileView()->scrollToBottom(); // FIXME always correct behaviour? else { /// Editing this new element was cancelled, /// therefore remove it again d->model->removeRow(d->model->rowCount() - 1); } } void KBibTeXPart::newCommentTriggered() { QSharedPointer newComment = QSharedPointer(new Comment()); d->model->insertRow(newComment, d->model->rowCount()); d->partWidget->fileView()->setSelectedElement(newComment); if (d->partWidget->fileView()->editElement(newComment)) d->partWidget->fileView()->scrollToBottom(); // FIXME always correct behaviour? else { /// Editing this new element was cancelled, /// therefore remove it again d->model->removeRow(d->model->rowCount() - 1); } } void KBibTeXPart::updateActions() { FileModel *model = d->partWidget != nullptr && d->partWidget->fileView() != nullptr ? d->partWidget->fileView()->fileModel() : nullptr; if (model == nullptr) return; bool emptySelection = d->partWidget->fileView()->selectedElements().isEmpty(); d->elementEditAction->setEnabled(!emptySelection); d->editCopyAction->setEnabled(!emptySelection); d->editCopyReferencesAction->setEnabled(!emptySelection); d->editCutAction->setEnabled(!emptySelection && isReadWrite()); d->editPasteAction->setEnabled(isReadWrite()); d->editDeleteAction->setEnabled(!emptySelection && isReadWrite()); d->elementFindPDFAction->setEnabled(!emptySelection && isReadWrite()); d->entryApplyDefaultFormatString->setEnabled(!emptySelection && isReadWrite()); d->colorLabelContextMenu->menuAction()->setEnabled(!emptySelection && isReadWrite()); d->colorLabelContextMenuAction->setEnabled(!emptySelection && isReadWrite()); int numDocumentsToView = d->updateViewDocumentMenu(); /// enable menu item only if there is at least one document to view d->elementViewDocumentAction->setEnabled(!emptySelection && numDocumentsToView > 0); /// activate sub-menu only if there are at least two documents to view d->elementViewDocumentAction->setMenu(numDocumentsToView > 1 ? d->viewDocumentMenu : nullptr); d->elementViewDocumentAction->setToolTip(numDocumentsToView == 1 ? (*d->viewDocumentMenu->actions().constBegin())->text() : QString()); /// update list of references which can be sent to LyX QStringList references; if (d->partWidget->fileView()->selectionModel() != nullptr) { const QModelIndexList mil = d->partWidget->fileView()->selectionModel()->selectedRows(); references.reserve(mil.size()); for (const QModelIndex &index : mil) { const QSharedPointer entry = model->element(d->partWidget->fileView()->sortFilterProxyModel()->mapToSource(index).row()).dynamicCast(); if (!entry.isNull()) references << entry->id(); } } d->lyx->setReferences(references); } void KBibTeXPart::fileExternallyChange(const QString &path) { /// Should never happen: triggering this slot for non-local or invalid URLs if (!url().isValid() || !url().isLocalFile()) return; /// Should never happen: triggering this slot for filenames not being the opened file if (path != url().toLocalFile()) { qCWarning(LOG_KBIBTEX_PARTS) << "Got file modification warning for wrong file: " << path << "!=" << url().toLocalFile(); return; } /// Stop watching file while asking for user interaction if (!path.isEmpty()) d->fileSystemWatcher.removePath(path); else qCWarning(LOG_KBIBTEX_PARTS) << "No filename to stop watching"; if (KMessageBox::warningContinueCancel(widget(), i18n("The file '%1' has changed on disk.\n\nReload file or ignore changes on disk?", path), i18n("File changed externally"), KGuiItem(i18n("Reload file"), QIcon::fromTheme(QStringLiteral("edit-redo"))), KGuiItem(i18n("Ignore on-disk changes"), QIcon::fromTheme(QStringLiteral("edit-undo")))) == KMessageBox::Continue) { d->openFile(QUrl::fromLocalFile(path), path); /// No explicit call to QFileSystemWatcher.addPath(...) necessary, /// openFile(...) has done that already } else { /// Even if the user did not request reloaded the file, /// still resume watching file for future external changes if (!path.isEmpty()) d->fileSystemWatcher.addPath(path); else qCWarning(LOG_KBIBTEX_PARTS) << "path is Empty"; } } #include "part.moc"