From 77b1bcf5451757787eda8aa5c8ffb9d064ca3d70 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 24 Jan 2019 01:15:23 +0100 Subject: [PATCH 1/2] Convert "Customize importer" dialog to JavaFX --- .../java/org/jabref/gui/DialogService.java | 9 + .../java/org/jabref/gui/FXDialogService.java | 12 + src/main/java/org/jabref/gui/JabRefFrame.java | 2 +- .../actions/ManageCustomImportsAction.java | 10 +- .../ExportCustomizationDialogView.java | 30 +- .../importer/ImportCustomizationDialog.fxml | 22 ++ .../importer/ImportCustomizationDialog.java | 368 +++--------------- .../ImportCustomizationDialogViewModel.java | 134 +++++++ .../jabref/gui/importer/ZipFileChooser.java | 241 ------------ .../gui/util/ViewModelTableRowFactory.java | 16 + .../org/jabref/gui/util/ZipFileChooser.java | 84 ++++ 11 files changed, 348 insertions(+), 580 deletions(-) create mode 100644 src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.fxml create mode 100644 src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java delete mode 100644 src/main/java/org/jabref/gui/importer/ZipFileChooser.java create mode 100644 src/main/java/org/jabref/gui/util/ZipFileChooser.java diff --git a/src/main/java/org/jabref/gui/DialogService.java b/src/main/java/org/jabref/gui/DialogService.java index f776d192671..d1da9b44c4c 100644 --- a/src/main/java/org/jabref/gui/DialogService.java +++ b/src/main/java/org/jabref/gui/DialogService.java @@ -1,5 +1,6 @@ package org.jabref.gui; +import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.List; @@ -247,4 +248,12 @@ Optional showCustomButtonDialogAndWait(Alert.AlertType type, String */ boolean showPrintDialog(PrinterJob job); + /** + * Shows a new dialog that list all files contained in the given archive and which lets the user select one of these + * files. The method doesn't return until the displayed open dialog is dismissed. The return value specifies the + * file chosen by the user or an empty {@link Optional} if no selection has been made. + * + * @return the selected file or an empty {@link Optional} if no file has been selected + */ + Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException; } diff --git a/src/main/java/org/jabref/gui/FXDialogService.java b/src/main/java/org/jabref/gui/FXDialogService.java index 60593d1edf9..59283b7b200 100644 --- a/src/main/java/org/jabref/gui/FXDialogService.java +++ b/src/main/java/org/jabref/gui/FXDialogService.java @@ -1,6 +1,7 @@ package org.jabref.gui; import java.io.File; +import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; @@ -8,6 +9,7 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.zip.ZipFile; import javafx.concurrent.Task; import javafx.print.PrinterJob; @@ -31,6 +33,7 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.gui.util.ZipFileChooser; import org.jabref.logic.l10n.Localization; import org.controlsfx.dialog.ExceptionDialog; @@ -300,4 +303,13 @@ private FileChooser getConfiguredFileChooser(FileDialogConfiguration fileDialogC public boolean showPrintDialog(PrinterJob job) { return job.showPrintDialog(mainWindow); } + + @Override + public Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException { + try (ZipFile zipFile = new ZipFile(archivePath.toFile(), ZipFile.OPEN_READ)) { + return new ZipFileChooser(zipFile).showAndWait(); + } catch (NoClassDefFoundError exc) { + throw new IOException("Could not instantiate ZIP-archive reader.", exc); + } + } } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 66e4643e1d2..d8fd07cb6f2 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -928,7 +928,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), factory.createMenuItem(StandardActions.SETUP_GENERAL_FIELDS, new SetupGeneralFieldsAction()), - factory.createMenuItem(StandardActions.MANAGE_CUSTOM_IMPORTS, new ManageCustomImportsAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CUSTOM_IMPORTS, new ManageCustomImportsAction()), factory.createMenuItem(StandardActions.MANAGE_CUSTOM_EXPORTS, new ManageCustomExportsAction()), factory.createMenuItem(StandardActions.MANAGE_EXTERNAL_FILETYPES, new EditExternalFileTypesAction()), factory.createMenuItem(StandardActions.MANAGE_JOURNALS, new ManageJournalsAction()), diff --git a/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java b/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java index 5359168805c..e36ea7ac07c 100644 --- a/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java +++ b/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java @@ -1,21 +1,15 @@ package org.jabref.gui.actions; -import org.jabref.gui.JabRefFrame; import org.jabref.gui.importer.ImportCustomizationDialog; public class ManageCustomImportsAction extends SimpleCommand { - private final JabRefFrame jabRefFrame; - - public ManageCustomImportsAction(JabRefFrame jabRefFrame) { - this.jabRefFrame = jabRefFrame; + public ManageCustomImportsAction() { } @Override public void execute() { - ImportCustomizationDialog ecd = new ImportCustomizationDialog(jabRefFrame); - ecd.setVisible(true); - + new ImportCustomizationDialog().showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/exporter/ExportCustomizationDialogView.java b/src/main/java/org/jabref/gui/exporter/ExportCustomizationDialogView.java index 0ca7d26c5ee..506f829ad66 100644 --- a/src/main/java/org/jabref/gui/exporter/ExportCustomizationDialogView.java +++ b/src/main/java/org/jabref/gui/exporter/ExportCustomizationDialogView.java @@ -41,22 +41,13 @@ public ExportCustomizationDialogView() { .load() .setAsDialogPane(this); - ControlHelper.setAction(addButton, getDialogPane(), event -> addExporter()); - ControlHelper.setAction(modifyButton, getDialogPane(), event -> modifyExporter()); - ControlHelper.setAction(removeButton, getDialogPane(), event -> removeExporter()); - ControlHelper.setAction(closeButton, getDialogPane(), event -> saveAndClose()); - } - - private void addExporter() { - viewModel.addExporter(); - } - - private void modifyExporter() { - viewModel.modifyExporter(); - } - - private void removeExporter() { - viewModel.removeExporters(); + ControlHelper.setAction(addButton, getDialogPane(), event -> viewModel.addExporter()); + ControlHelper.setAction(modifyButton, getDialogPane(), event -> viewModel.modifyExporter()); + ControlHelper.setAction(removeButton, getDialogPane(), event -> viewModel.removeExporters()); + ControlHelper.setAction(closeButton, getDialogPane(), event -> { + viewModel.saveToPrefs(); + close(); + }); } @FXML @@ -69,9 +60,4 @@ private void initialize() { layoutColumn.setCellValueFactory(cellData -> cellData.getValue().layoutFileName()); extensionColumn.setCellValueFactory(cellData -> cellData.getValue().extension()); } - - private void saveAndClose() { - viewModel.saveToPrefs(); - close(); - } -} \ No newline at end of file +} diff --git a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.fxml b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.fxml new file mode 100644 index 00000000000..ef7ac89babb --- /dev/null +++ b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.fxml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.java b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.java index 3cbfa285a47..7dd005727e5 100644 --- a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialog.java @@ -1,320 +1,72 @@ package org.jabref.gui.importer; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Optional; -import java.util.zip.ZipFile; +import javax.inject.Inject; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableColumnModel; +import javafx.beans.property.ReadOnlyStringWrapper; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.Tooltip; -import org.jabref.Globals; import org.jabref.gui.DialogService; -import org.jabref.gui.JabRefDialog; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.help.HelpAction; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.gui.util.FileDialogConfiguration; -import org.jabref.logic.help.HelpFile; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.importer.fileformat.CustomImporter; +import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.StandardFileType; -import org.jabref.preferences.JabRefPreferences; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Dialog to manage custom importers. - */ -public class ImportCustomizationDialog extends JabRefDialog { - - private static final Logger LOGGER = LoggerFactory.getLogger(ImportCustomizationDialog.class); - - // Column widths for import customization dialog table: - private static final int COL_0_WIDTH = 200; - private static final int COL_1_WIDTH = 80; - private static final int COL_2_WIDTH = 200; - - private static final int COL_3_WIDTH = 200; - - private final JTable customImporterTable; - - public ImportCustomizationDialog(final JabRefFrame frame) { - super(Localization.lang("Manage custom imports"), false, ImportCustomizationDialog.class); - - DialogService dialogService = frame.getDialogService(); - - ImportTableModel tableModel = new ImportTableModel(); - customImporterTable = new JTable(tableModel); - TableColumnModel cm = customImporterTable.getColumnModel(); - cm.getColumn(0).setPreferredWidth(COL_0_WIDTH); - cm.getColumn(1).setPreferredWidth(COL_1_WIDTH); - cm.getColumn(2).setPreferredWidth(COL_2_WIDTH); - cm.getColumn(3).setPreferredWidth(COL_3_WIDTH); - JScrollPane sp = new JScrollPane(customImporterTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - customImporterTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - customImporterTable.setPreferredScrollableViewportSize(getSize()); - if (customImporterTable.getRowCount() > 0) { - customImporterTable.setRowSelectionInterval(0, 0); - } - - JButton addFromFolderButton = new JButton(Localization.lang("Add from folder")); - addFromFolderButton.addActionListener(e -> { - - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .addExtensionFilter(StandardFileType.CLASS, StandardFileType.JAR) - .withDefaultExtension(StandardFileType.JAR) - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); - - Optional selectedFile = DefaultTaskExecutor - .runInJavaFXThread(() -> dialogService.showFileOpenDialog(fileDialogConfiguration)); - - if (selectedFile.isPresent() && (selectedFile.get().getParent() != null)) { - String chosenFileStr = selectedFile.get().toString(); - - try { - String basePath = selectedFile.get().getParent().toString(); - String className = pathToClass(basePath, new File(chosenFileStr)); - CustomImporter importer = new CustomImporter(basePath, className); - - addOrReplaceImporter(importer); - customImporterTable.revalidate(); - customImporterTable.repaint(); - } catch (Exception exc) { - dialogService.showErrorDialogAndWait(Localization.lang("Could not instantiate %0", chosenFileStr), exc); - } catch (NoClassDefFoundError exc) { - dialogService.showErrorDialogAndWait( - Localization.lang("Could not instantiate %0. Have you chosen the correct package path?", chosenFileStr), - exc); - } - - } - }); - addFromFolderButton - .setToolTipText(Localization.lang("Add a (compiled) custom Importer class from a class path.") - + "\n" + Localization.lang("The path need not be on the classpath of JabRef.")); - - JButton addFromJarButton = new JButton(Localization.lang("Add from JAR")); - addFromJarButton.addActionListener(e -> { - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .addExtensionFilter(StandardFileType.JAR, StandardFileType.ZIP) - .withDefaultExtension(StandardFileType.JAR) - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); - - Optional jarZipFile = DefaultTaskExecutor - .runInJavaFXThread(() -> dialogService.showFileOpenDialog(fileDialogConfiguration)); - - if (jarZipFile.isPresent()) { - try (ZipFile zipFile = new ZipFile(jarZipFile.get().toFile(), ZipFile.OPEN_READ)) { - ZipFileChooser zipFileChooser = new ZipFileChooser(this, zipFile); - zipFileChooser.setVisible(true); - customImporterTable.revalidate(); - customImporterTable.repaint(10); - } catch (IOException exc) { - LOGGER.info("Could not open ZIP-archive.", exc); - dialogService.showErrorDialogAndWait( - Localization.lang("Could not open %0", jarZipFile.get().toString()) + "\n" - + Localization.lang("Have you chosen the correct package path?"), - exc); - } catch (NoClassDefFoundError exc) { - LOGGER.info("Could not instantiate ZIP-archive reader.", exc); - dialogService.showErrorDialogAndWait( - Localization.lang("Could not instantiate %0", jarZipFile.get().toString()) + "\n" - + Localization.lang("Have you chosen the correct package path?"), - exc); - } - } - }); - addFromJarButton - .setToolTipText(Localization.lang("Add a (compiled) custom Importer class from a ZIP-archive.") - + "\n" + Localization.lang("The ZIP-archive need not be on the classpath of JabRef.")); - - JButton showDescButton = new JButton(Localization.lang("Show description")); - showDescButton.addActionListener(e -> { - int row = customImporterTable.getSelectedRow(); - if (row == -1) { - dialogService.showWarningDialogAndWait( - Localization.lang("Manage custom imports"), - Localization.lang("Please select an importer.")); - } else { - CustomImporter importer = ((ImportTableModel) customImporterTable.getModel()).getImporter(row); - dialogService.showWarningDialogAndWait( - Localization.lang("Manage custom imports"), - importer.getDescription()); - } +import org.jabref.preferences.PreferencesService; + +import com.airhacks.afterburner.views.ViewLoader; +import org.fxmisc.easybind.EasyBind; + +public class ImportCustomizationDialog extends BaseDialog { + + @FXML private ButtonType addButton; + @FXML private ButtonType removeButton; + @FXML private ButtonType closeButton; + @FXML private TableView importerTable; + @FXML private TableColumn nameColumn; + @FXML private TableColumn classColumn; + @FXML private TableColumn basePathColumn; + + @Inject private DialogService dialogService; + @Inject private PreferencesService preferences; + @Inject private JournalAbbreviationLoader loader; + private ImportCustomizationDialogViewModel viewModel; + + public ImportCustomizationDialog() { + this.setTitle(Localization.lang("Manage custom imports")); + + ViewLoader.view(this) + .load() + .setAsDialogPane(this); + + ((Button) getDialogPane().lookupButton(addButton)).setTooltip(new Tooltip( + Localization.lang("Add a (compiled) custom Importer class from a class path.") + + "\n" + Localization.lang("The path need not be on the classpath of JabRef."))); + ControlHelper.setAction(addButton, getDialogPane(), event -> viewModel.addImporter()); + ControlHelper.setAction(removeButton, getDialogPane(), event -> viewModel.removeSelectedImporter()); + ControlHelper.setAction(closeButton, getDialogPane(), event -> { + viewModel.saveToPrefs(); + close(); }); - - JButton removeButton = new JButton(Localization.lang("Remove")); - removeButton.addActionListener(e -> { - int row = customImporterTable.getSelectedRow(); - if (row == -1) { - dialogService.showWarningDialogAndWait( - Localization.lang("Manage custom imports"), - Localization.lang("Please select an importer.")); - } else { - customImporterTable.removeRowSelectionInterval(row, row); - Globals.prefs.customImports - .remove(((ImportTableModel) customImporterTable.getModel()).getImporter(row)); - Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(), - Globals.prefs.getXMPPreferences(), Globals.getFileUpdateMonitor()); - customImporterTable.revalidate(); - customImporterTable.repaint(); - } - }); - - Action closeAction = new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }; - - JButton closeButton = new JButton(Localization.lang("Close")); - closeButton.addActionListener(closeAction); - - JButton helpButton = new HelpAction(HelpFile.CUSTOM_IMPORTS).getHelpButton(); - - // Key bindings: - JPanel mainPanel = new JPanel(); - ActionMap am = mainPanel.getActionMap(); - InputMap im = mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", closeAction); - mainPanel.setLayout(new BorderLayout()); - mainPanel.add(sp, BorderLayout.CENTER); - JPanel buttons = new JPanel(); - ButtonBarBuilder bb = new ButtonBarBuilder(buttons); - buttons.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); - bb.addGlue(); - bb.addButton(addFromFolderButton); - bb.addButton(addFromJarButton); - bb.addButton(showDescButton); - bb.addButton(removeButton); - bb.addButton(closeButton); - bb.addUnrelatedGap(); - bb.addButton(helpButton); - bb.addGlue(); - - getContentPane().add(mainPanel, BorderLayout.CENTER); - getContentPane().add(buttons, BorderLayout.SOUTH); - this.setSize(getSize()); - pack(); - customImporterTable.requestFocus(); } - /* - * (non-Javadoc) - * @see java.awt.Component#getSize() - */ - @Override - public Dimension getSize() { - int width = COL_0_WIDTH + COL_1_WIDTH + COL_2_WIDTH + COL_3_WIDTH; - return new Dimension(width, width / 2); + @FXML + private void initialize() { + viewModel = new ImportCustomizationDialogViewModel(preferences, dialogService); + importerTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + importerTable.itemsProperty().bind(viewModel.importersProperty()); + EasyBind.listBind(viewModel.selectedImportersProperty(), importerTable.getSelectionModel().getSelectedItems()); + nameColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getName())); + classColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getClassName())); + basePathColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getBasePath().toString())); + new ViewModelTableRowFactory() + .withTooltip(CustomImporter::getDescription) + .install(importerTable); } - - /** - * Converts a path relative to a base-path into a class name. - * - * @param basePath base path - * @param path path that includes base-path as a prefix - * @return class name - */ - private static String pathToClass(String basePath, File path) { - String className = null; - File actualPath = path; - // remove leading basepath from path - while (!actualPath.equals(new File(basePath))) { - className = actualPath.getName() + (className == null ? "" : "." + className); - actualPath = actualPath.getParentFile(); - } - if (className != null) { - int lastDot = className.lastIndexOf('.'); - if (lastDot < 0) { - return className; - } - className = className.substring(0, lastDot); - } - return className; - } - - /** - * Adds an importer to the model that underlies the custom importers. - * - * @param importer importer - */ - public void addOrReplaceImporter(CustomImporter importer) { - Globals.prefs.customImports.replaceImporter(importer); - Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(), - Globals.prefs.getXMPPreferences(), Globals.getFileUpdateMonitor()); - ((ImportTableModel) customImporterTable.getModel()).fireTableDataChanged(); - } - - /** - * Table model for the custom importer table. - */ - private class ImportTableModel extends AbstractTableModel { - - private final String[] columnNames = new String[] {Localization.lang("Import name"), - Localization.lang("Command line id"), Localization.lang("Importer class"), - Localization.lang("Contained in")}; - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - Object value = null; - CustomImporter importer = getImporter(rowIndex); - if (columnIndex == 0) { - value = importer.getName(); - } else if (columnIndex == 1) { - value = importer.getName(); - } else if (columnIndex == 2) { - value = importer.getClassName(); - } else if (columnIndex == 3) { - value = importer.getBasePath(); - } - return value; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public int getRowCount() { - return Globals.prefs.customImports.size(); - } - - @Override - public String getColumnName(int col) { - return columnNames[col]; - } - - public CustomImporter getImporter(int rowIndex) { - CustomImporter[] importers = Globals.prefs.customImports - .toArray(new CustomImporter[Globals.prefs.customImports.size()]); - return importers[rowIndex]; - } - } - } diff --git a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java new file mode 100644 index 00000000000..ef204f9c4fb --- /dev/null +++ b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java @@ -0,0 +1,134 @@ +package org.jabref.gui.importer; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Optional; + +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.collections.FXCollections; + +import org.jabref.Globals; +import org.jabref.gui.AbstractViewModel; +import org.jabref.gui.DialogService; +import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.logic.importer.fileformat.CustomImporter; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.util.StandardFileType; +import org.jabref.logic.util.io.FileUtil; +import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreferencesService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ImportCustomizationDialogViewModel extends AbstractViewModel { + + private static final Logger LOGGER = LoggerFactory.getLogger(ImportCustomizationDialogViewModel.class); + + private final ListProperty importers; + private final ListProperty selectedImporters = new SimpleListProperty<>(FXCollections.observableArrayList()); + + private final PreferencesService preferences; + private final DialogService dialogService; + + public ImportCustomizationDialogViewModel(PreferencesService preferences, DialogService dialogService) { + this.preferences = preferences; + this.dialogService = dialogService; + this.importers = new SimpleListProperty<>(FXCollections.observableArrayList(Globals.prefs.customImports)); + } + + /** + * Converts a path relative to a base-path into a class name. + * + * @param basePath base path + * @param path path that includes base-path as a prefix + * @return class name + */ + private static String pathToClass(String basePath, Path path) { + String className = FileUtil.relativize(path, Collections.singletonList(Paths.get(basePath))).toString(); + if (className != null) { + int lastDot = className.lastIndexOf('.'); + if (lastDot < 0) { + return className; + } + className = className.substring(0, lastDot); + } + return className; + } + + public void addImporter() { + FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() + .addExtensionFilter(StandardFileType.CLASS, StandardFileType.JAR, StandardFileType.ZIP) + .withDefaultExtension(StandardFileType.CLASS) + .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)) + .build(); + + Optional selectedFile = dialogService.showFileOpenDialog(fileDialogConfiguration); + + if (selectedFile.isPresent() && (selectedFile.get().getParent() != null)) { + boolean isArchive = FileUtil.getFileExtension(selectedFile.get()) + .filter(extension -> extension.equalsIgnoreCase("jar") || extension.equalsIgnoreCase("zip")) + .isPresent(); + + if (isArchive) { + try { + Optional selectedFileInArchive = dialogService.showFileOpenFromArchiveDialog(selectedFile.get()); + if (selectedFileInArchive.isPresent()) { + String className = selectedFileInArchive.get().substring(0, selectedFileInArchive.get().lastIndexOf('.')).replace( + "/", "."); + CustomImporter importer = new CustomImporter(selectedFile.get().toAbsolutePath().toString(), className); + importers.add(importer); + } + } catch (IOException exc) { + LOGGER.error("Could not open ZIP-archive.", exc); + dialogService.showErrorDialogAndWait( + Localization.lang("Could not open %0", selectedFile.get().toString()) + "\n" + + Localization.lang("Have you chosen the correct package path?"), + exc); + } catch (ClassNotFoundException exc) { + LOGGER.error("Could not instantiate importer", exc); + dialogService.showErrorDialogAndWait( + Localization.lang("Could not instantiate %0 %1", "importer"), + exc); + } + } else { + try { + String basePath = selectedFile.get().getParent().toString(); + String className = pathToClass(basePath, selectedFile.get()); + CustomImporter importer = new CustomImporter(basePath, className); + + importers.add(importer); + } catch (Exception exc) { + LOGGER.error("Could not instantiate importer", exc); + dialogService.showErrorDialogAndWait(Localization.lang("Could not instantiate %0", selectedFile.get().toString()), exc); + } catch (NoClassDefFoundError exc) { + LOGGER.error("Could not find class while instantiating importer", exc); + dialogService.showErrorDialogAndWait( + Localization.lang("Could not instantiate %0. Have you chosen the correct package path?", selectedFile.get().toString()), + exc); + } + } + } + } + + public void removeSelectedImporter() { + importers.removeAll(selectedImporters); + } + + public void saveToPrefs() { + Globals.prefs.customImports.clear(); + Globals.prefs.customImports.addAll(importers); + Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(), Globals.prefs.getXMPPreferences(), Globals.getFileUpdateMonitor()); + } + + public ListProperty selectedImportersProperty() { + return selectedImporters; + } + + public ListProperty importersProperty() { + return importers; + } +} diff --git a/src/main/java/org/jabref/gui/importer/ZipFileChooser.java b/src/main/java/org/jabref/gui/importer/ZipFileChooser.java deleted file mode 100644 index f4a1f78f5dd..00000000000 --- a/src/main/java/org/jabref/gui/importer/ZipFileChooser.java +++ /dev/null @@ -1,241 +0,0 @@ -package org.jabref.gui.importer; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import javax.swing.Box; -import javax.swing.JButton; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableColumnModel; - -import org.jabref.gui.JabRefDialog; -import org.jabref.logic.importer.fileformat.CustomImporter; -import org.jabref.logic.l10n.Localization; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Dialog to allow users to choose a file contained in a ZIP file. - */ -class ZipFileChooser extends JabRefDialog { - - private static final Logger LOGGER = LoggerFactory.getLogger(ZipFileChooser.class); - - - /** - * New ZIP file chooser. - * - * @param importCustomizationDialog Owner of the file chooser - * @param zipFile ZIP-Fle to choose from, must be readable - */ - public ZipFileChooser(ImportCustomizationDialog importCustomizationDialog, ZipFile zipFile) { - super(importCustomizationDialog, Localization.lang("Select file from ZIP-archive"), false, ZipFileChooser.class); - - - ZipFileChooserTableModel tableModel = new ZipFileChooserTableModel(zipFile, getSelectableZipEntries(zipFile)); - JTable table = new JTable(tableModel); - TableColumnModel cm = table.getColumnModel(); - cm.getColumn(0).setPreferredWidth(200); - cm.getColumn(1).setPreferredWidth(150); - cm.getColumn(2).setPreferredWidth(100); - JScrollPane sp = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - table.setPreferredScrollableViewportSize(new Dimension(500, 150)); - if (table.getRowCount() > 0) { - table.setRowSelectionInterval(0, 0); - } - - // cancel: no entry is selected - JButton cancelButton = new JButton(Localization.lang("Cancel")); - cancelButton.addActionListener(e -> dispose()); - // ok: get selected class and check if it is instantiable as an importer - JButton okButton = new JButton(Localization.lang("OK")); - okButton.addActionListener(e -> { - int row = table.getSelectedRow(); - if (row == -1) { - JOptionPane.showMessageDialog(this, Localization.lang("Please select an importer.")); - } else { - ZipFileChooserTableModel model = (ZipFileChooserTableModel) table.getModel(); - ZipEntry tempZipEntry = model.getZipEntry(row); - String className = tempZipEntry.getName().substring(0, tempZipEntry.getName().lastIndexOf('.')).replace( - "/", "."); - - try { - CustomImporter importer = new CustomImporter(model.getZipFile().getName(), className); - importCustomizationDialog.addOrReplaceImporter(importer); - dispose(); - } catch (ClassNotFoundException exc) { - LOGGER.warn("Could not instantiate importer: " + className, exc); - JOptionPane.showMessageDialog(this, Localization.lang("Could not instantiate %0 %1", - className + ":\n", exc.getMessage())); - } - } - }); - - - // Key bindings: - JPanel mainPanel = new JPanel(); - //ActionMap am = mainPanel.getActionMap(); - //InputMap im = mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - //im.put(Globals.getKeyPrefs().getKey(KeyBinds.CLOSE_DIALOG), "close"); - //am.put("close", closeAction); - mainPanel.setLayout(new BorderLayout()); - mainPanel.add(sp, BorderLayout.CENTER); - - JPanel optionsPanel = new JPanel(); - optionsPanel.add(okButton); - optionsPanel.add(cancelButton); - optionsPanel.add(Box.createHorizontalStrut(5)); - - getContentPane().add(mainPanel, BorderLayout.CENTER); - getContentPane().add(optionsPanel, BorderLayout.SOUTH); - this.setSize(getSize()); - pack(); - this.setLocationRelativeTo(importCustomizationDialog); - table.requestFocus(); - } - - /** - * Entries that can be selected with this dialog. - * - * @param zipFile ZIP-File - * @return entries that can be selected - */ - private static List getSelectableZipEntries(ZipFile zipFile) { - List entries = new ArrayList<>(); - Enumeration e = zipFile.entries(); - for (ZipEntry entry : Collections.list(e)) { - if (!entry.isDirectory() && entry.getName().endsWith(".class")) { - entries.add(entry); - } - } - return entries; - } - - /* - * (non-Javadoc) - * @see java.awt.Component#getSize() - */ - @Override - public Dimension getSize() { - return new Dimension(400, 300); - } - - - /** - * Table model for the ZIP archive contents. - * - *

Contains one row for each entry. - * Does not contain rows for directory entries.

- * - *

The columns contain information about ZIP file entries: - *

  1. - * name {@link String} - *
  2. - * time of last modification {@link Date} - *
  3. - * size (uncompressed) {@link Long} - *

- */ - private static class ZipFileChooserTableModel extends AbstractTableModel { - - private final List columnNames = Arrays.asList(Localization.lang("Name"), - Localization.lang("Last modified"), Localization.lang("Size")); - private final List rows; - private final ZipFile zipFile; - - - ZipFileChooserTableModel(ZipFile zipFile, List rows) { - super(); - this.rows = rows; - this.zipFile = zipFile; - } - - /* - * (non-Javadoc) - * @see javax.swing.table.TableModel#getColumnCount() - */ - @Override - public int getColumnCount() { - return columnNames.size(); - } - - /* - * (non-Javadoc) - * @see javax.swing.table.TableModel#getRowCount() - */ - @Override - public int getRowCount() { - return this.rows.size(); - } - - /* - * (non-Javadoc) - * @see javax.swing.table.TableModel#getColumnName(int) - */ - @Override - public String getColumnName(int col) { - return columnNames.get(col); - } - - /** - * ZIP-File entry at the given row index. - * - * @param rowIndex row index - * @return ZIP file entry - */ - public ZipEntry getZipEntry(int rowIndex) { - return this.rows.get(rowIndex); - } - - /** - * ZIP file which contains all entries of this model. - * - * @return zip file - */ - public ZipFile getZipFile() { - return this.zipFile; - } - - /* - * (non-Javadoc) - * @see javax.swing.table.TableModel#getValueAt(int, int) - */ - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - Object value = null; - ZipEntry entry = getZipEntry(rowIndex); - if (columnIndex == 0) { - value = entry.getName(); - } else if (columnIndex == 1) { - value = ZonedDateTime.ofInstant(new Date(entry.getTime()).toInstant(), - ZoneId.systemDefault()) - .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)); - } else if (columnIndex == 2) { - value = entry.getSize(); - } - return value; - } - } - -} diff --git a/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java index 6e053fc3a40..78d50765935 100644 --- a/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java +++ b/src/main/java/org/jabref/gui/util/ViewModelTableRowFactory.java @@ -8,6 +8,7 @@ import javafx.scene.control.ContextMenu; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; +import javafx.scene.control.Tooltip; import javafx.scene.control.TreeTableCell; import javafx.scene.input.DragEvent; import javafx.scene.input.KeyCode; @@ -16,6 +17,8 @@ import javafx.scene.input.MouseEvent; import javafx.util.Callback; +import org.jabref.model.strings.StringUtil; + import org.reactfx.util.TriConsumer; /** @@ -33,6 +36,7 @@ public class ViewModelTableRowFactory implements Callback, Table private BiConsumer toOnDragExited; private BiConsumer toOnDragOver; private TriConsumer, S, ? super MouseDragEvent> toOnMouseDragEntered; + private Callback toTooltip; public ViewModelTableRowFactory withOnMouseClickedEvent(BiConsumer onMouseClickedEvent) { this.onMouseClickedEvent = onMouseClickedEvent; @@ -84,10 +88,22 @@ public ViewModelTableRowFactory setOnDragOver(BiConsumer withTooltip(Callback toTooltip) { + this.toTooltip = toTooltip; + return this; + } + @Override public TableRow call(TableView tableView) { TableRow row = new TableRow<>(); + if (toTooltip != null) { + String tooltipText = toTooltip.call(row.getItem()); + if (StringUtil.isNotBlank(tooltipText)) { + row.setTooltip(new Tooltip(tooltipText)); + } + } + if (onMouseClickedEvent != null) { row.setOnMouseClicked(event -> { if (!row.isEmpty()) { diff --git a/src/main/java/org/jabref/gui/util/ZipFileChooser.java b/src/main/java/org/jabref/gui/util/ZipFileChooser.java new file mode 100644 index 00000000000..3335dcaaea6 --- /dev/null +++ b/src/main/java/org/jabref/gui/util/ZipFileChooser.java @@ -0,0 +1,84 @@ +package org.jabref.gui.util; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javafx.beans.property.ReadOnlyLongWrapper; +import javafx.beans.property.ReadOnlyStringWrapper; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.control.ButtonType; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; + +import org.jabref.logic.l10n.Localization; + +/** + * Dialog to allow users to choose a file contained in a ZIP file. + */ +public class ZipFileChooser extends BaseDialog { + + /** + * New ZIP file chooser. + * + * @param zipFile ZIP-Fle to choose from, must be readable + */ + public ZipFileChooser(ZipFile zipFile) { + setTitle(Localization.lang("Select file from ZIP-archive")); + + TableView table = new TableView<>(getSelectableZipEntries(zipFile)); + TableColumn nameColumn = new TableColumn<>(Localization.lang("Name")); + TableColumn modifiedColumn = new TableColumn<>(Localization.lang("Last modified")); + TableColumn sizeColumn = new TableColumn<>(Localization.lang("Size")); + table.getColumns().add(nameColumn); + table.getColumns().add(modifiedColumn); + table.getColumns().add(sizeColumn); + nameColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getName())); + modifiedColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper( + ZonedDateTime.ofInstant(new Date(data.getValue().getTime()).toInstant(), + ZoneId.systemDefault()) + .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)))); + sizeColumn.setCellValueFactory(data -> new ReadOnlyLongWrapper(data.getValue().getSize())); + table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + + getDialogPane().setContent(table); + + getDialogPane().getButtonTypes().setAll( + ButtonType.OK, + ButtonType.CANCEL + ); + + setResultConverter(button -> { + if (button == ButtonType.OK) { + return table.getSelectionModel().getSelectedItem().getName(); + } else { + return null; + } + }); + } + + /** + * Entries that can be selected with this dialog. + * + * @param zipFile ZIP-File + * @return entries that can be selected + */ + private static ObservableList getSelectableZipEntries(ZipFile zipFile) { + ObservableList entries = FXCollections.observableArrayList(); + Enumeration e = zipFile.entries(); + for (ZipEntry entry : Collections.list(e)) { + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + entries.add(entry); + } + } + return entries; + } +} From 0903eb1b97bcc0b9de139d036909074f7023e9ed Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 24 Jan 2019 21:26:56 +0100 Subject: [PATCH 2/2] Use nio methods to access contents of zip files --- .../java/org/jabref/gui/DialogService.java | 2 +- .../java/org/jabref/gui/FXDialogService.java | 7 +- .../ImportCustomizationDialogViewModel.java | 4 +- .../org/jabref/gui/util/ZipFileChooser.java | 66 +++++++++++-------- src/main/resources/l10n/JabRef_en.properties | 14 ---- 5 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/jabref/gui/DialogService.java b/src/main/java/org/jabref/gui/DialogService.java index d1da9b44c4c..947fa1c66a0 100644 --- a/src/main/java/org/jabref/gui/DialogService.java +++ b/src/main/java/org/jabref/gui/DialogService.java @@ -255,5 +255,5 @@ Optional showCustomButtonDialogAndWait(Alert.AlertType type, String * * @return the selected file or an empty {@link Optional} if no file has been selected */ - Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException; + Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException; } diff --git a/src/main/java/org/jabref/gui/FXDialogService.java b/src/main/java/org/jabref/gui/FXDialogService.java index 59283b7b200..93470689c79 100644 --- a/src/main/java/org/jabref/gui/FXDialogService.java +++ b/src/main/java/org/jabref/gui/FXDialogService.java @@ -2,6 +2,8 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; @@ -9,7 +11,6 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Collectors; -import java.util.zip.ZipFile; import javafx.concurrent.Task; import javafx.print.PrinterJob; @@ -305,8 +306,8 @@ public boolean showPrintDialog(PrinterJob job) { } @Override - public Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException { - try (ZipFile zipFile = new ZipFile(archivePath.toFile(), ZipFile.OPEN_READ)) { + public Optional showFileOpenFromArchiveDialog(Path archivePath) throws IOException { + try (FileSystem zipFile = FileSystems.newFileSystem(archivePath, null)) { return new ZipFileChooser(zipFile).showAndWait(); } catch (NoClassDefFoundError exc) { throw new IOException("Could not instantiate ZIP-archive reader.", exc); diff --git a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java index ef204f9c4fb..8ab6ba58277 100644 --- a/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportCustomizationDialogViewModel.java @@ -75,9 +75,9 @@ public void addImporter() { if (isArchive) { try { - Optional selectedFileInArchive = dialogService.showFileOpenFromArchiveDialog(selectedFile.get()); + Optional selectedFileInArchive = dialogService.showFileOpenFromArchiveDialog(selectedFile.get()); if (selectedFileInArchive.isPresent()) { - String className = selectedFileInArchive.get().substring(0, selectedFileInArchive.get().lastIndexOf('.')).replace( + String className = selectedFileInArchive.get().toString().substring(0, selectedFileInArchive.get().toString().lastIndexOf('.')).replace( "/", "."); CustomImporter importer = new CustomImporter(selectedFile.get().toAbsolutePath().toString(), className); importers.add(importer); diff --git a/src/main/java/org/jabref/gui/util/ZipFileChooser.java b/src/main/java/org/jabref/gui/util/ZipFileChooser.java index 3335dcaaea6..74049324e9d 100644 --- a/src/main/java/org/jabref/gui/util/ZipFileChooser.java +++ b/src/main/java/org/jabref/gui/util/ZipFileChooser.java @@ -1,14 +1,14 @@ package org.jabref.gui.util; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; +import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyLongWrapper; import javafx.beans.property.ReadOnlyStringWrapper; @@ -24,29 +24,43 @@ /** * Dialog to allow users to choose a file contained in a ZIP file. */ -public class ZipFileChooser extends BaseDialog { +public class ZipFileChooser extends BaseDialog { /** * New ZIP file chooser. * * @param zipFile ZIP-Fle to choose from, must be readable */ - public ZipFileChooser(ZipFile zipFile) { + public ZipFileChooser(FileSystem zipFile) throws IOException { setTitle(Localization.lang("Select file from ZIP-archive")); - TableView table = new TableView<>(getSelectableZipEntries(zipFile)); - TableColumn nameColumn = new TableColumn<>(Localization.lang("Name")); - TableColumn modifiedColumn = new TableColumn<>(Localization.lang("Last modified")); - TableColumn sizeColumn = new TableColumn<>(Localization.lang("Size")); + TableView table = new TableView<>(getSelectableZipEntries(zipFile)); + TableColumn nameColumn = new TableColumn<>(Localization.lang("Name")); + TableColumn modifiedColumn = new TableColumn<>(Localization.lang("Last modified")); + TableColumn sizeColumn = new TableColumn<>(Localization.lang("Size")); table.getColumns().add(nameColumn); table.getColumns().add(modifiedColumn); table.getColumns().add(sizeColumn); - nameColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getName())); - modifiedColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper( - ZonedDateTime.ofInstant(new Date(data.getValue().getTime()).toInstant(), - ZoneId.systemDefault()) - .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)))); - sizeColumn.setCellValueFactory(data -> new ReadOnlyLongWrapper(data.getValue().getSize())); + nameColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().toString())); + modifiedColumn.setCellValueFactory(data -> { + try { + return new ReadOnlyStringWrapper( + ZonedDateTime.ofInstant(Files.getLastModifiedTime(data.getValue()).toInstant(), + ZoneId.systemDefault()) + .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))); + } catch (IOException e) { + // Ignore + return new ReadOnlyStringWrapper(""); + } + }); + sizeColumn.setCellValueFactory(data -> { + try { + return new ReadOnlyLongWrapper(Files.size(data.getValue())); + } catch (IOException e) { + // Ignore + return new ReadOnlyLongWrapper(0); + } + }); table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); getDialogPane().setContent(table); @@ -58,7 +72,7 @@ public ZipFileChooser(ZipFile zipFile) { setResultConverter(button -> { if (button == ButtonType.OK) { - return table.getSelectionModel().getSelectedItem().getName(); + return table.getSelectionModel().getSelectedItem(); } else { return null; } @@ -71,14 +85,12 @@ public ZipFileChooser(ZipFile zipFile) { * @param zipFile ZIP-File * @return entries that can be selected */ - private static ObservableList getSelectableZipEntries(ZipFile zipFile) { - ObservableList entries = FXCollections.observableArrayList(); - Enumeration e = zipFile.entries(); - for (ZipEntry entry : Collections.list(e)) { - if (!entry.isDirectory() && entry.getName().endsWith(".class")) { - entries.add(entry); - } - } - return entries; + private static ObservableList getSelectableZipEntries(FileSystem zipFile) throws IOException { + Path rootDir = zipFile.getRootDirectories().iterator().next(); + + return FXCollections.observableArrayList( + Files.walk(rootDir) + .filter(file -> file.endsWith(".class")) + .collect(Collectors.toList())); } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index d451fa524d2..121851eeae8 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -40,17 +40,10 @@ Add=Add Add\ a\ (compiled)\ custom\ Importer\ class\ from\ a\ class\ path.=Add a (compiled) custom Importer class from a class path. The\ path\ need\ not\ be\ on\ the\ classpath\ of\ JabRef.=The path need not be on the classpath of JabRef. -Add\ a\ (compiled)\ custom\ Importer\ class\ from\ a\ ZIP-archive.=Add a (compiled) custom Importer class from a ZIP-archive. -The\ ZIP-archive\ need\ not\ be\ on\ the\ classpath\ of\ JabRef.=The ZIP-archive need not be on the classpath of JabRef. - Add\ a\ regular\ expression\ for\ the\ key\ pattern.=Add a regular expression for the key pattern. Add\ selected\ entries\ to\ this\ group=Add selected entries to this group -Add\ from\ folder=Add from folder - -Add\ from\ JAR=Add from JAR - Add\ subgroup=Add subgroup Add\ to\ group=Add to group @@ -155,8 +148,6 @@ Clear=Clear Clear\ fields=Clear fields -Close=Close - Close\ entry=Close entry Close\ dialog=Close dialog @@ -167,7 +158,6 @@ Close\ window=Close window Closed\ library=Closed library -Command\ line\ id=Command line id Comments=Comments Contained\ in=Contained in @@ -787,8 +777,6 @@ Please\ enter\ the\ field\ to\ search\ (e.g.\ keywords)\ and\ the\ keywor Please\ enter\ the\ string's\ label=Please enter the string's label -Please\ select\ an\ importer.=Please select an importer. - Please\ restart\ JabRef\ for\ preferences\ to\ take\ effect.=Please restart JabRef for preferences to take effect. Possible\ duplicate\ entries=Possible duplicate entries @@ -972,8 +960,6 @@ Show\ BibTeX\ source\ by\ default=Show BibTeX source by default Show\ confirmation\ dialog\ when\ deleting\ entries=Show confirmation dialog when deleting entries -Show\ description=Show description - Show\ file\ column=Show file column Show\ last\ names\ only=Show last names only