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