001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.File; 007import java.io.IOException; 008import java.util.List; 009 010import javax.swing.JOptionPane; 011 012import org.openstreetmap.josm.Main; 013import org.openstreetmap.josm.actions.ExtensionFileFilter; 014import org.openstreetmap.josm.gui.HelpAwareOptionPane; 015import org.openstreetmap.josm.gui.Notification; 016import org.openstreetmap.josm.gui.progress.ProgressMonitor; 017import org.openstreetmap.josm.gui.util.GuiHelper; 018 019/** 020 * Abstract file importer. 021 * @since 1637 022 * @since 10386 (signature) 023 */ 024public abstract class FileImporter implements Comparable<FileImporter> { 025 026 /** 027 * The extension file filter used to accept files. 028 */ 029 public final ExtensionFileFilter filter; 030 031 private boolean enabled; 032 033 /** 034 * Constructs a new {@code FileImporter} with the given extension file filter. 035 * @param filter The extension file filter 036 */ 037 public FileImporter(ExtensionFileFilter filter) { 038 this.filter = filter; 039 this.enabled = true; 040 } 041 042 /** 043 * Determines if this file importer accepts the given file. 044 * @param pathname The file to test 045 * @return {@code true} if this file importer accepts the given file, {@code false} otherwise 046 */ 047 public boolean acceptFile(File pathname) { 048 return filter.acceptName(pathname.getName()); 049 } 050 051 /** 052 * A batch importer is a file importer that prefers to read multiple files at the same time. 053 * @return {@code true} if this importer is a batch importer 054 */ 055 public boolean isBatchImporter() { 056 return false; 057 } 058 059 /** 060 * Needs to be implemented if isBatchImporter() returns false. 061 * @param file file to import 062 * @param progressMonitor progress monitor 063 * @throws IOException if any I/O error occurs 064 * @throws IllegalDataException if invalid data is read 065 */ 066 public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException { 067 throw new IOException(tr("Could not import ''{0}''.", file.getName())); 068 } 069 070 /** 071 * Needs to be implemented if isBatchImporter() returns true. 072 * @param files files to import 073 * @param progressMonitor progress monitor 074 * @throws IOException if any I/O error occurs 075 * @throws IllegalDataException if invalid data is read 076 */ 077 public void importData(List<File> files, ProgressMonitor progressMonitor) throws IOException, IllegalDataException { 078 throw new IOException(tr("Could not import files.")); 079 } 080 081 /** 082 * Wrapper to {@link #importData(File, ProgressMonitor)} to give meaningful output if things go wrong. 083 * @param f data file to import 084 * @param progressMonitor progress monitor 085 * @return true if data import was successful 086 */ 087 public boolean importDataHandleExceptions(File f, ProgressMonitor progressMonitor) { 088 try { 089 Main.info("Open file: " + f.getAbsolutePath() + " (" + f.length() + " bytes)"); 090 importData(f, progressMonitor); 091 return true; 092 } catch (IllegalDataException e) { 093 Throwable cause = e.getCause(); 094 if (cause instanceof ImportCancelException) { 095 displayCancel(cause); 096 } else { 097 displayError(f, e); 098 } 099 return false; 100 } catch (IOException e) { 101 displayError(f, e); 102 return false; 103 } 104 } 105 106 private static void displayError(File f, Exception e) { 107 Main.error(e); 108 HelpAwareOptionPane.showMessageDialogInEDT( 109 Main.parent, 110 tr("<html>Could not read file ''{0}''.<br>Error is:<br>{1}</html>", f.getName(), e.getMessage()), 111 tr("Error"), 112 JOptionPane.ERROR_MESSAGE, null 113 ); 114 } 115 116 private static void displayCancel(final Throwable t) { 117 GuiHelper.runInEDTAndWait(() -> { 118 Notification note = new Notification(t.getMessage()); 119 note.setIcon(JOptionPane.INFORMATION_MESSAGE); 120 note.setDuration(Notification.TIME_SHORT); 121 note.show(); 122 }); 123 } 124 125 /** 126 * Wrapper to {@link #importData(List, ProgressMonitor)} to give meaningful output if things go wrong. 127 * @param files data files to import 128 * @param progressMonitor progress monitor 129 * @return true if data import was successful 130 */ 131 public boolean importDataHandleExceptions(List<File> files, ProgressMonitor progressMonitor) { 132 try { 133 Main.info("Open "+files.size()+" files"); 134 importData(files, progressMonitor); 135 return true; 136 } catch (IOException | IllegalDataException e) { 137 Main.error(e); 138 HelpAwareOptionPane.showMessageDialogInEDT( 139 Main.parent, 140 tr("<html>Could not read files.<br>Error is:<br>{0}</html>", e.getMessage()), 141 tr("Error"), 142 JOptionPane.ERROR_MESSAGE, null 143 ); 144 return false; 145 } 146 } 147 148 /** 149 * If multiple files (with multiple file formats) are selected, 150 * they are opened in the order of their priorities. 151 * Highest priority comes first. 152 * @return priority 153 */ 154 public double getPriority() { 155 return 0; 156 } 157 158 @Override 159 public int compareTo(FileImporter other) { 160 return Double.compare(this.getPriority(), other.getPriority()); 161 } 162 163 /** 164 * Returns the enabled state of this {@code FileImporter}. When enabled, it is listed and usable in "File->Open" dialog. 165 * @return true if this {@code FileImporter} is enabled 166 * @since 5459 167 */ 168 public final boolean isEnabled() { 169 return enabled; 170 } 171 172 /** 173 * Sets the enabled state of the {@code FileImporter}. When enabled, it is listed and usable in "File->Open" dialog. 174 * @param enabled true to enable this {@code FileImporter}, false to disable it 175 * @since 5459 176 */ 177 public final void setEnabled(boolean enabled) { 178 this.enabled = enabled; 179 } 180}