diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd5571d47b..211eb9d2513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue when importing into current library an erroneous message "import cancelled" is displayed even though import is successful. [#6266](https://github.com/JabRef/jabref/issues/6266) - We fixed an issue where custom jstyles for Open/LibreOffice where not saved correctly. [#6170](https://github.com/JabRef/jabref/issues/6170) - We fixed an issue where the INSPIRE fetcher was no longer working [#6229](https://github.com/JabRef/jabref/issues/6229) +- We fixed an issue where custom exports with an uppercase file extension could not be selected for "Copy...-> Export to Clipboard" [#6285](https://github.com/JabRef/jabref/issues/6285) + - We fixed the display of icon both in the main table and linked file editor. [#6169](https://github.com/JabRef/jabref/issues/6169) - We fixed the paste entry command in the menu and toolbar, that did not do anything. [#6293](https://github.com/JabRef/jabref/issues/6293) - We fixed an issue where the windows installer did not create an entry in the start menu [bug report in the forum](https://discourse.jabref.org/t/error-while-fetching-from-doi/2018/3) diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index ae79b4d341f..3325287841c 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -715,7 +715,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.COPY_KEY_AND_TITLE, new CopyMoreAction(StandardActions.COPY_KEY_AND_TITLE, dialogService, stateManager, Globals.clipboardManager, prefs)), factory.createMenuItem(StandardActions.COPY_KEY_AND_LINK, new CopyMoreAction(StandardActions.COPY_KEY_AND_LINK, dialogService, stateManager, Globals.clipboardManager, prefs)), factory.createMenuItem(StandardActions.COPY_CITATION_PREVIEW, new CopyCitationAction(CitationStyleOutputFormat.HTML, dialogService, stateManager, Globals.clipboardManager, prefs.getPreviewPreferences())), - factory.createMenuItem(StandardActions.EXPORT_SELECTED_TO_CLIPBOARD, new ExportToClipboardAction(this, dialogService))), + factory.createMenuItem(StandardActions.EXPORT_SELECTED_TO_CLIPBOARD, new ExportToClipboardAction(this, dialogService, Globals.exportFactory, Globals.clipboardManager, Globals.TASK_EXECUTOR))), factory.createMenuItem(StandardActions.PASTE, new EditAction(StandardActions.PASTE, this, stateManager)), diff --git a/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java b/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java index 3505738d7d6..040f90a1eff 100644 --- a/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java +++ b/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java @@ -5,24 +5,28 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import javafx.scene.input.ClipboardContent; import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.ClipBoardManager; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.exporter.Exporter; +import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.FileType; import org.jabref.logic.util.OS; +import org.jabref.logic.util.StandardFileType; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; @@ -34,21 +38,30 @@ public class ExportToClipboardAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(ExportToClipboardAction.class); // Only text based exporters can be used - private static final List SUPPORTED_FILETYPES = Arrays.asList("txt", "rtf", "rdf", "xml", "html", "htm", "csv", "ris"); + private static final Set SUPPORTED_FILETYPES = Set.of(StandardFileType.TXT, StandardFileType.RTF, StandardFileType.RDF, StandardFileType.XML, StandardFileType.HTML, StandardFileType.CSV, StandardFileType.RIS); private JabRefFrame frame; private final DialogService dialogService; private BasePanel panel; private final List entries = new ArrayList<>(); + private final ExporterFactory exporterFactory; + private final ClipBoardManager clipBoardManager; + private final TaskExecutor taskExecutor; - public ExportToClipboardAction(JabRefFrame frame, DialogService dialogService) { + public ExportToClipboardAction(JabRefFrame frame, DialogService dialogService, ExporterFactory exporterFactory, ClipBoardManager clipBoardManager, TaskExecutor taskExecutor) { this.frame = frame; this.dialogService = dialogService; + this.exporterFactory = exporterFactory; + this.clipBoardManager = clipBoardManager; + this.taskExecutor = taskExecutor; } - public ExportToClipboardAction(BasePanel panel, DialogService dialogService) { + public ExportToClipboardAction(BasePanel panel, DialogService dialogService, ExporterFactory exporterFactory, ClipBoardManager clipBoardManager, TaskExecutor taskExecutor) { this.panel = panel; this.dialogService = dialogService; + this.exporterFactory = exporterFactory; + this.clipBoardManager = clipBoardManager; + this.taskExecutor = taskExecutor; } @Override @@ -62,10 +75,10 @@ public void execute() { return; } - List exporters = Globals.exportFactory.getExporters().stream() - .sorted(Comparator.comparing(Exporter::getName)) - .filter(exporter -> SUPPORTED_FILETYPES.containsAll(exporter.getFileType().getExtensions())) - .collect(Collectors.toList()); + List exporters = exporterFactory.getExporters().stream() + .sorted(Comparator.comparing(Exporter::getName)) + .filter(exporter -> SUPPORTED_FILETYPES.contains(exporter.getFileType())) + .collect(Collectors.toList()); // Find default choice, if any Exporter defaultChoice = exporters.stream() @@ -74,12 +87,15 @@ public void execute() { .orElse(null); Optional selectedExporter = dialogService.showChoiceDialogAndWait(Localization.lang("Export"), Localization.lang("Select export format"), - Localization.lang("Export"), defaultChoice, exporters); + Localization.lang("Export"), defaultChoice, exporters); selectedExporter.ifPresent(exporter -> BackgroundTask.wrap(() -> exportToClipboard(exporter)) - .onSuccess(this::setContentToClipboard) - .onFailure(ex -> { /* swallow as already logged */ }) - .executeWith(Globals.TASK_EXECUTOR)); + .onSuccess(this::setContentToClipboard) + .onFailure(ex -> { + LOGGER.error("Error exporting to clipboard", ex); + dialogService.showErrorDialogAndWait("Error exporting to clipboard", ex); + }) + .executeWith(taskExecutor)); } private ExportResult exportToClipboard(Exporter exporter) throws Exception { @@ -109,9 +125,7 @@ private ExportResult exportToClipboard(Exporter exporter) throws Exception { // Read the file and put the contents on the clipboard: return new ExportResult(readFileToString(tmp), exporter.getFileType()); - } catch (Exception e) { - LOGGER.error("Error exporting to clipboard", e); - throw new Exception("Rethrow ", e); + } finally { // Clean up: if ((tmp != null) && Files.exists(tmp)) { @@ -135,7 +149,7 @@ private void setContentToClipboard(ExportResult result) { clipboardContent.putRtf(result.content); } clipboardContent.putString(result.content); - Globals.clipboardManager.setContent(clipboardContent); + this.clipBoardManager.setContent(clipboardContent); dialogService.notify(Localization.lang("Entries exported to clipboard") + ": " + entries.size()); @@ -151,6 +165,7 @@ private String readFileToString(Path tmp) throws IOException { } private static class ExportResult { + final String content; final FileType fileType; diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 58e5088175e..86726216200 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -99,7 +99,7 @@ private static Menu createCopySubMenu(BasePanel panel, ActionFactory factory, Di copySpecialMenu.getItems().add(factory.createMenuItem(StandardActions.COPY_CITATION_PREVIEW, new CopyCitationAction(CitationStyleOutputFormat.HTML, dialogService, stateManager, Globals.clipboardManager, previewPreferences))); } - copySpecialMenu.getItems().add(factory.createMenuItem(StandardActions.EXPORT_TO_CLIPBOARD, new ExportToClipboardAction(panel, dialogService))); + copySpecialMenu.getItems().add(factory.createMenuItem(StandardActions.EXPORT_TO_CLIPBOARD, new ExportToClipboardAction(panel, dialogService, Globals.exportFactory, Globals.clipboardManager, Globals.TASK_EXECUTOR))); return copySpecialMenu; } } diff --git a/src/main/java/org/jabref/gui/preview/CopyCitationAction.java b/src/main/java/org/jabref/gui/preview/CopyCitationAction.java index 0edabf2af5b..4c353fd615a 100644 --- a/src/main/java/org/jabref/gui/preview/CopyCitationAction.java +++ b/src/main/java/org/jabref/gui/preview/CopyCitationAction.java @@ -58,6 +58,7 @@ public CopyCitationAction(CitationStyleOutputFormat outputFormat, DialogService this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); } + @Override public void execute() { BackgroundTask.wrap(this::generateCitations) .onFailure(ex -> LOGGER.error("Error while copying citations to the clipboard", ex)) diff --git a/src/main/java/org/jabref/logic/exporter/TemplateExporter.java b/src/main/java/org/jabref/logic/exporter/TemplateExporter.java index 57d2a1f1c03..5390611bd8d 100644 --- a/src/main/java/org/jabref/logic/exporter/TemplateExporter.java +++ b/src/main/java/org/jabref/logic/exporter/TemplateExporter.java @@ -83,7 +83,7 @@ public TemplateExporter(String displayName, String consoleName, String lfFileNam */ public TemplateExporter(String name, String lfFileName, String extension, LayoutFormatterPreferences layoutPreferences, SavePreferences savePreferences) { - this(name, name, lfFileName, null, StandardFileType.newFileType(extension), layoutPreferences, savePreferences); + this(name, name, lfFileName, null, StandardFileType.fromExtensions(extension), layoutPreferences, savePreferences); } /** diff --git a/src/main/java/org/jabref/logic/util/StandardFileType.java b/src/main/java/org/jabref/logic/util/StandardFileType.java index e89aa27982f..d56c19ea7d1 100644 --- a/src/main/java/org/jabref/logic/util/StandardFileType.java +++ b/src/main/java/org/jabref/logic/util/StandardFileType.java @@ -3,11 +3,15 @@ import java.util.Arrays; import java.util.List; +import org.jabref.model.util.OptionalUtil; + /** * - * @implNote Enter the extensions without a dot! The dot is added implicitly. + * @implNote Enter the extensions in lowercase without a dot! The dot is added implicitly. + * */ public enum StandardFileType implements FileType { + BIBTEXML("bibx", "xml"), ENDNOTE("ref", "enw"), ISI("isi", "txt"), @@ -21,7 +25,7 @@ public enum StandardFileType implements FileType { CITATION_STYLE("csl"), CLASS("class"), CSV("csv"), - HTML("html"), + HTML("html", "htm"), JAR("jar"), JAVA_KEYSTORE("jks"), JSTYLE("jstyle"), @@ -51,12 +55,13 @@ public List getExtensions() { return extensions; } - public static FileType newFileType(String... extensions) { - for (int i = 0; i < extensions.length; i++) { - if (extensions[i].contains(".")) { - extensions[i] = extensions[i].substring(extensions[i].indexOf('.') + 1); - } - } - return () -> Arrays.asList(extensions); + public static FileType fromExtensions(String... extensions) { + var exts = Arrays.asList(extensions); + + return OptionalUtil.orElse(Arrays.stream(StandardFileType.values()) + .filter(field -> field.getExtensions().stream().anyMatch(elem -> exts.contains(elem))) + .findAny(), + new UnknownFileType(extensions)); } + } diff --git a/src/main/java/org/jabref/logic/util/UnknownFileType.java b/src/main/java/org/jabref/logic/util/UnknownFileType.java new file mode 100644 index 00000000000..e057caa3974 --- /dev/null +++ b/src/main/java/org/jabref/logic/util/UnknownFileType.java @@ -0,0 +1,46 @@ +package org.jabref.logic.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class UnknownFileType implements FileType { + + private final List extensions; + + public UnknownFileType(String... extensions) { + for (int i = 0; i < extensions.length; i++) { + if (extensions[i].contains(".")) { + extensions[i] = extensions[i].substring(extensions[i].indexOf('.') + 1); + } + extensions[i] = extensions[i].toLowerCase(Locale.ROOT); + } + this.extensions = Arrays.asList(extensions); + } + + @Override + public List getExtensions() { + return extensions; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FileType)) { + return false; + } + FileType other = (FileType) o; + Collections.sort(extensions); + Collections.sort(other.getExtensions()); + return extensions.equals(other.getExtensions()); + } + + @Override + public int hashCode() { + return Objects.hash(extensions); + } +}