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.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Dialog to allow users to choose a file contained in a ZIP file. */ class ZipFileChooser extends JabRefDialog { private static final Log LOGGER = LogFactory.getLog(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<ZipEntry> getSelectableZipEntries(ZipFile zipFile) { List<ZipEntry> entries = new ArrayList<>(); Enumeration<? extends ZipEntry> 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. * * <p>Contains one row for each entry. * Does not contain rows for directory entries.</p> * * <p>The columns contain information about ZIP file entries: * <ol><li> * name {@link String} * </li><li> * time of last modification {@link Date} * </li><li> * size (uncompressed) {@link Long} * </li></ol></p> */ private static class ZipFileChooserTableModel extends AbstractTableModel { private final List<String> columnNames = Arrays.asList(Localization.lang("Name"), Localization.lang("Last modified"), Localization.lang("Size")); private final List<ZipEntry> rows; private final ZipFile zipFile; ZipFileChooserTableModel(ZipFile zipFile, List<ZipEntry> 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; } } }