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(new Runnable() {
118            @Override
119            public void run() {
120                Notification note = new Notification(t.getMessage());
121                note.setIcon(JOptionPane.INFORMATION_MESSAGE);
122                note.setDuration(Notification.TIME_SHORT);
123                note.show();
124            }
125        });
126    }
127
128    /**
129     * Wrapper to {@link #importData(List, ProgressMonitor)} to give meaningful output if things go wrong.
130     * @param files data files to import
131     * @param progressMonitor progress monitor
132     * @return true if data import was successful
133     */
134    public boolean importDataHandleExceptions(List<File> files, ProgressMonitor progressMonitor) {
135        try {
136            Main.info("Open "+files.size()+" files");
137            importData(files, progressMonitor);
138            return true;
139        } catch (IOException | IllegalDataException e) {
140            Main.error(e);
141            HelpAwareOptionPane.showMessageDialogInEDT(
142                    Main.parent,
143                    tr("<html>Could not read files.<br>Error is:<br>{0}</html>", e.getMessage()),
144                    tr("Error"),
145                    JOptionPane.ERROR_MESSAGE, null
146            );
147            return false;
148        }
149    }
150
151    /**
152     * If multiple files (with multiple file formats) are selected,
153     * they are opened in the order of their priorities.
154     * Highest priority comes first.
155     * @return priority
156     */
157    public double getPriority() {
158        return 0;
159    }
160
161    @Override
162    public int compareTo(FileImporter other) {
163        return Double.compare(this.getPriority(), other.getPriority());
164    }
165
166    /**
167     * Returns the enabled state of this {@code FileImporter}. When enabled, it is listed and usable in "File-&gt;Open" dialog.
168     * @return true if this {@code FileImporter} is enabled
169     * @since 5459
170     */
171    public final boolean isEnabled() {
172        return enabled;
173    }
174
175    /**
176     * Sets the enabled state of the {@code FileImporter}. When enabled, it is listed and usable in "File-&gt;Open" dialog.
177     * @param enabled true to enable this {@code FileImporter}, false to disable it
178     * @since 5459
179     */
180    public final void setEnabled(boolean enabled) {
181        this.enabled = enabled;
182    }
183}