Skip to content

Commit

Permalink
Write embedded bib in addition to XMP metadata (#8037)
Browse files Browse the repository at this point in the history
* EmbeddedBibFilePdfExporter

* Standard Action

* Gui triggers

* Fix empty optional

* CLI triggers

* Localization

* CHANGELOG

* use System streams instead of Logger for user out

* Typo in CHANGELOG.md

Co-authored-by: Christoph <siedlerkiller@gmail.com>

Co-authored-by: Benedikt Tutzer <benedikt.tutzer@tuwien.ac.at>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
  • Loading branch information
3 people committed Aug 31, 2021
1 parent df83c9d commit 577f51c
Show file tree
Hide file tree
Showing 22 changed files with 499 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We merged the barely used ImportSettingsTab and the CustomizationTab in the preferences into one single tab and moved the option to allow Integers in Edition Fields in Bibtex-Mode to the EntryEditor tab. [#7849](https://github.com/JabRef/jabref/pull/7849)
- We moved the export order in the preferences from `File` to `Import and Export`. [#7935](https://github.com/JabRef/jabref/pull/7935)
- We reworked the export order in the preferences and the save order in the library preferences. You can now set more than three sort criteria in your library preferences. [#7935](https://github.com/JabRef/jabref/pull/7935)
- The metadata-to-pdf actions now also embeds the bibfile to the PDF. [#8037](https://github.com/JabRef/jabref/pull/8037)

### Fixed

Expand Down
78 changes: 55 additions & 23 deletions src/main/java/org/jabref/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.logic.JabRefException;
import org.jabref.logic.bibtex.FieldWriterPreferences;
import org.jabref.logic.citationkeypattern.CitationKeyGenerator;
import org.jabref.logic.exporter.AtomicFileWriter;
import org.jabref.logic.exporter.BibDatabaseWriter;
import org.jabref.logic.exporter.BibtexDatabaseWriter;
import org.jabref.logic.exporter.EmbeddedBibFilePdfExporter;
import org.jabref.logic.exporter.Exporter;
import org.jabref.logic.exporter.ExporterFactory;
import org.jabref.logic.exporter.SavePreferences;
Expand Down Expand Up @@ -51,6 +53,7 @@
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.DummyFileUpdateMonitor;
import org.jabref.model.util.FileHelper;
Expand Down Expand Up @@ -224,13 +227,22 @@ private List<ParserResult> processArguments() {
automaticallySetFileLinks(loaded);
}

if (cli.isWriteXMPtoPdf()) {
if (cli.isWriteXMPtoPdf() && cli.isEmbeddBibfileInPdf() || cli.isWriteMetadatatoPdf() && (cli.isWriteXMPtoPdf() || cli.isEmbeddBibfileInPdf())) {
System.err.println("Give only one of [writeXMPtoPdf, embeddBibfileInPdf, writeMetadatatoPdf]");
}

if (cli.isWriteMetadatatoPdf() || cli.isWriteXMPtoPdf() || cli.isEmbeddBibfileInPdf()) {
if (!loaded.isEmpty()) {
writeXMPtoPdf(loaded,
cli.getWriteXMPtoPdf(),
writeMetadatatoPdf(loaded,
cli.getWriteMetadatatoPdf(),
preferencesService.getDefaultEncoding(),
preferencesService.getXmpPreferences(),
preferencesService.getFilePreferences());
preferencesService.getFilePreferences(),
preferencesService.getDefaultBibDatabaseMode(),
Globals.entryTypesManager,
preferencesService.getFieldWriterPreferences(),
cli.isWriteXMPtoPdf() || cli.isWriteMetadatatoPdf(),
cli.isEmbeddBibfileInPdf() || cli.isWriteMetadatatoPdf());
}
}

Expand Down Expand Up @@ -258,7 +270,7 @@ private List<ParserResult> processArguments() {
return loaded;
}

private void writeXMPtoPdf(List<ParserResult> loaded, String filesAndCitekeys, Charset encoding, XmpPreferences xmpPreferences, FilePreferences filePreferences) {
private void writeMetadatatoPdf(List<ParserResult> loaded, String filesAndCitekeys, Charset encoding, XmpPreferences xmpPreferences, FilePreferences filePreferences, BibDatabaseMode databaseMode, BibEntryTypesManager entryTypesManager, FieldWriterPreferences fieldWriterPreferences, boolean writeXMP, boolean embeddBibfile) {
if (loaded.isEmpty()) {
LOGGER.error("The write xmp option depends on a valid import option.");
return;
Expand All @@ -268,10 +280,11 @@ private void writeXMPtoPdf(List<ParserResult> loaded, String filesAndCitekeys, C
BibDatabase dataBase = pr.getDatabase();

XmpPdfExporter xmpPdfExporter = new XmpPdfExporter(xmpPreferences);
EmbeddedBibFilePdfExporter embeddedBibFilePdfExporter = new EmbeddedBibFilePdfExporter(databaseMode, entryTypesManager, fieldWriterPreferences);

if ("all".equals(filesAndCitekeys)) {
for (BibEntry entry : dataBase.getEntries()) {
writeXMPtoPDFsOfEntry(databaseContext, entry.getCitationKey().orElse("<no cite key defined>"), entry, encoding, filePreferences, xmpPdfExporter);
writeMetadatatoPDFsOfEntry(databaseContext, entry.getCitationKey().orElse("<no cite key defined>"), entry, encoding, filePreferences, xmpPdfExporter, embeddedBibFilePdfExporter, writeXMP, embeddBibfile);
}
return;
}
Expand All @@ -286,48 +299,66 @@ private void writeXMPtoPdf(List<ParserResult> loaded, String filesAndCitekeys, C
}
}

writeXMPtoPdfByCitekey(databaseContext, dataBase, citeKeys, encoding, filePreferences, xmpPdfExporter);
writeXMPtoPdfByFileNames(databaseContext, dataBase, pdfs, encoding, filePreferences, xmpPdfExporter);
writeMetadatatoPdfByCitekey(databaseContext, dataBase, citeKeys, encoding, filePreferences, xmpPdfExporter, embeddedBibFilePdfExporter, writeXMP, embeddBibfile);
writeMetadatatoPdfByFileNames(databaseContext, dataBase, pdfs, encoding, filePreferences, xmpPdfExporter, embeddedBibFilePdfExporter, writeXMP, embeddBibfile);

}

private void writeXMPtoPDFsOfEntry(BibDatabaseContext databaseContext, String citeKey, BibEntry entry, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter) {
private void writeMetadatatoPDFsOfEntry(BibDatabaseContext databaseContext, String citeKey, BibEntry entry, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter, EmbeddedBibFilePdfExporter embeddedBibFilePdfExporter, boolean writeXMP, boolean embeddBibfile) {
try {
if (xmpPdfExporter.exportToAllFilesOfEntry(databaseContext, encoding, filePreferences, entry, List.of(entry))) {
LOGGER.info(String.format("Successfully written XMP metadata on at least one linked file of %s", citeKey));
} else {
LOGGER.error(String.format("Cannot write XMP metadata on any linked files of %s. Make sure there is at least one linked file and the path is correct.", citeKey));
if (writeXMP) {
if (xmpPdfExporter.exportToAllFilesOfEntry(databaseContext, encoding, filePreferences, entry, List.of(entry))) {
System.out.println(String.format("Successfully written XMP metadata on at least one linked file of %s", citeKey));
} else {
System.err.println(String.format("Cannot write XMP metadata on any linked files of %s. Make sure there is at least one linked file and the path is correct.", citeKey));
}
}
if (embeddBibfile) {
if (embeddedBibFilePdfExporter.exportToAllFilesOfEntry(databaseContext, encoding, filePreferences, entry, List.of(entry))) {
System.out.println(String.format("Successfully embedded metadata on at least one linked file of %s", citeKey));
} else {
System.out.println(String.format("Cannot embedd metadata on any linked files of %s. Make sure there is at least one linked file and the path is correct.", citeKey));
}
}
} catch (Exception e) {
LOGGER.error(String.format("Failed writing XMP metadata on a linked file of %s.", citeKey));
LOGGER.error(String.format("Failed writing metadata on a linked file of %s.", citeKey));
}
}

private void writeXMPtoPdfByCitekey(BibDatabaseContext databaseContext, BibDatabase dataBase, Vector<String> citeKeys, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter) {
private void writeMetadatatoPdfByCitekey(BibDatabaseContext databaseContext, BibDatabase dataBase, Vector<String> citeKeys, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter, EmbeddedBibFilePdfExporter embeddedBibFilePdfExporter, boolean writeXMP, boolean embeddBibfile) {
for (String citeKey : citeKeys) {
List<BibEntry> bibEntryList = dataBase.getEntriesByCitationKey(citeKey);
if (bibEntryList.isEmpty()) {
LOGGER.error(String.format("Skipped - Cannot find %s in library.", citeKey));
System.err.println(String.format("Skipped - Cannot find %s in library.", citeKey));
continue;
}
for (BibEntry entry : bibEntryList) {
writeXMPtoPDFsOfEntry(databaseContext, citeKey, entry, encoding, filePreferences, xmpPdfExporter);
writeMetadatatoPDFsOfEntry(databaseContext, citeKey, entry, encoding, filePreferences, xmpPdfExporter, embeddedBibFilePdfExporter, writeXMP, embeddBibfile);
}
}
}

private void writeXMPtoPdfByFileNames(BibDatabaseContext databaseContext, BibDatabase dataBase, Vector<String> fileNames, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter) {
private void writeMetadatatoPdfByFileNames(BibDatabaseContext databaseContext, BibDatabase dataBase, Vector<String> fileNames, Charset encoding, FilePreferences filePreferences, XmpPdfExporter xmpPdfExporter, EmbeddedBibFilePdfExporter embeddedBibFilePdfExporter, boolean writeXMP, boolean embeddBibfile) {
for (String fileName : fileNames) {
Path filePath = Path.of(fileName);
if (!filePath.isAbsolute()) {
filePath = FileHelper.find(fileName, databaseContext.getFileDirectories(filePreferences)).orElse(FileHelper.find(fileName, List.of(Path.of("").toAbsolutePath())).orElse(filePath));
}
if (Files.exists(filePath)) {
try {
if (xmpPdfExporter.exportToFileByPath(databaseContext, dataBase, encoding, filePreferences, filePath)) {
LOGGER.info(String.format("Successfully written XMP metadata of at least one entry to %s", fileName));
} else {
LOGGER.error(String.format("File %s is not linked to any entry in database.", fileName));
if (writeXMP) {
if (xmpPdfExporter.exportToFileByPath(databaseContext, dataBase, encoding, filePreferences, filePath)) {
System.out.println(String.format("Successfully written XMP metadata of at least one entry to %s", fileName));
} else {
System.out.println(String.format("File %s is not linked to any entry in database.", fileName));
}
}
if (embeddBibfile) {
if (embeddedBibFilePdfExporter.exportToFileByPath(databaseContext, dataBase, encoding, filePreferences, filePath)) {
System.out.println(String.format("Successfully embedded XMP metadata of at least one entry to %s", fileName));
} else {
System.out.println(String.format("File %s is not linked to any entry in database.", fileName));
}
}
} catch (IOException e) {
LOGGER.error("Error accessing file '{}'.", fileName);
Expand Down Expand Up @@ -567,7 +598,8 @@ private void importPreferences() {
preferencesService.getLayoutFormatterPreferences(Globals.journalAbbreviationRepository);
SavePreferences savePreferences = preferencesService.getSavePreferencesForExport();
XmpPreferences xmpPreferences = preferencesService.getXmpPreferences();
Globals.exportFactory = ExporterFactory.create(customExporters, layoutPreferences, savePreferences, xmpPreferences);
BibDatabaseMode bibDatabaseMode = preferencesService.getDefaultBibDatabaseMode();
Globals.exportFactory = ExporterFactory.create(customExporters, layoutPreferences, savePreferences, xmpPreferences, bibDatabaseMode, Globals.entryTypesManager);
} catch (JabRefException ex) {
LOGGER.error("Cannot import preferences", ex);
}
Expand Down
32 changes: 29 additions & 3 deletions src/main/java/org/jabref/cli/JabRefCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,18 @@ public boolean isWriteXMPtoPdf() {
return cl.hasOption("writeXMPtoPdf");
}

public String getWriteXMPtoPdf() {
return cl.getOptionValue("writeXMPtoPdf");
public boolean isEmbeddBibfileInPdf() {
return cl.hasOption("embeddBibfileInPdf");
}

public boolean isWriteMetadatatoPdf() {
return cl.hasOption("writeMetadatatoPdf");
}

public String getWriteMetadatatoPdf() {
return cl.hasOption("writeMetadatatoPdf") ? cl.getOptionValue("writeMetadatatoPdf") :
cl.hasOption("writeXMPtoPdf") ? cl.getOptionValue("writeXMPtoPdf") :
cl.hasOption("embeddBibfileInPdf") ? cl.getOptionValue("embeddBibfileInPdf") : null;
}

private static Options getOptions() {
Expand Down Expand Up @@ -251,13 +261,29 @@ private static Options getOptions() {
.build());

options.addOption(Option
.builder("w")
.builder()
.longOpt("writeXMPtoPdf")
.desc(String.format("%s: '%s'", Localization.lang("Write BibTeXEntry as XMP metadata to PDF."), "-w pathToMyOwnPaper.pdf"))
.hasArg()
.argName("CITEKEY1[,CITEKEY2][,CITEKEYn] | PDF1[,PDF2][,PDFn] | all")
.build());

options.addOption(Option
.builder()
.longOpt("embeddBibfileInPdf")
.desc(String.format("%s: '%s'", Localization.lang("Embedd BibTeXEntry in PDF."), "-w pathToMyOwnPaper.pdf"))
.hasArg()
.argName("CITEKEY1[,CITEKEY2][,CITEKEYn] | PDF1[,PDF2][,PDFn] | all")
.build());

options.addOption(Option
.builder("w")
.longOpt("writeMetadatatoPdf")
.desc(String.format("%s: '%s'", Localization.lang("Write BibTeXEntry as metadata to PDF."), "-w pathToMyOwnPaper.pdf"))
.hasArg()
.argName("CITEKEY1[,CITEKEY2][,CITEKEYn] | PDF1[,PDF2][,PDFn] | all")
.build());

return options;
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
import org.jabref.gui.exporter.SaveAction;
import org.jabref.gui.exporter.SaveAllAction;
import org.jabref.gui.exporter.SaveDatabaseAction;
import org.jabref.gui.exporter.WriteXMPAction;
import org.jabref.gui.exporter.WriteMetadataToPdfAction;
import org.jabref.gui.externalfiles.AutoLinkFilesAction;
import org.jabref.gui.externalfiles.DownloadFullTextAction;
import org.jabref.gui.externalfiles.FindUnlinkedFilesAction;
Expand Down Expand Up @@ -810,7 +810,7 @@ private MenuBar createMenu() {

new SeparatorMenuItem(),

factory.createMenuItem(StandardActions.WRITE_XMP, new WriteXMPAction(stateManager, dialogService, prefs)),
factory.createMenuItem(StandardActions.WRITE_METADATA_TO_PDF, new WriteMetadataToPdfAction(stateManager, prefs.getDefaultBibDatabaseMode(), Globals.entryTypesManager, prefs.getFieldWriterPreferences(), dialogService, taskExecutor, prefs.getFilePreferences(), prefs.getXmpPreferences(), prefs.getDefaultEncoding())),
factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(dialogService, prefs, stateManager)),

new SeparatorMenuItem(),
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/jabref/gui/JabRefMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ private static void applyPreferences(PreferencesService preferences) {
preferences.getCustomExportFormats(Globals.journalAbbreviationRepository),
preferences.getLayoutFormatterPreferences(Globals.journalAbbreviationRepository),
preferences.getSavePreferencesForExport(),
preferences.getXmpPreferences());
preferences.getXmpPreferences(),
preferences.getDefaultBibDatabaseMode(),
Globals.entryTypesManager);

// Initialize protected terms loader
Globals.protectedTermsLoader = new ProtectedTermsLoader(preferences.getProtectedTermsPreferences());
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/actions/StandardActions.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public enum StandardActions implements Action {

PARSE_LATEX(Localization.lang("Search for citations in LaTeX files..."), IconTheme.JabRefIcons.LATEX_CITATIONS),
NEW_SUB_LIBRARY_FROM_AUX(Localization.lang("New sublibrary based on AUX file") + "...", Localization.lang("New BibTeX sublibrary") + Localization.lang("This feature generates a new library based on which entries are needed in an existing LaTeX document."), IconTheme.JabRefIcons.NEW),
WRITE_XMP(Localization.lang("Write XMP metadata to PDFs"), Localization.lang("Will write XMP metadata to the PDFs linked from selected entries."), KeyBinding.WRITE_XMP),
WRITE_METADATA_TO_PDF(Localization.lang("Write XMP metadata to PDFs"), Localization.lang("Will write XMP metadata to the PDFs linked from selected entries."), KeyBinding.WRITE_XMP),
START_NEW_STUDY(Localization.lang("Start new systematic literature review")),
SEARCH_FOR_EXISTING_STUDY(Localization.lang("Perform search for existing systematic literature review")),
OPEN_DATABASE_FOLDER(Localization.lang("Reveal in file explorer")),
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/jabref/gui/exporter/ExportCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public void execute() {
.sorted(Comparator.comparing(Exporter::getName))
.collect(Collectors.toList());

Globals.exportFactory = ExporterFactory.create(customExporters, layoutPreferences, savePreferences, xmpPreferences);
Globals.exportFactory = ExporterFactory.create(customExporters, layoutPreferences, savePreferences,
xmpPreferences, preferences.getDefaultBibDatabaseMode(), Globals.entryTypesManager);
FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
.addExtensionFilter(FileFilterConverter.exporterToExtensionFilter(exporters))
.withDefaultExtension(preferences.getImportExportPreferences().getLastExportExtension())
Expand Down
Loading

0 comments on commit 577f51c

Please sign in to comment.