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.MapView.LayerChangeListener;
016import org.openstreetmap.josm.gui.Notification;
017import org.openstreetmap.josm.gui.layer.Layer;
018import org.openstreetmap.josm.gui.progress.ProgressMonitor;
019import org.openstreetmap.josm.gui.util.GuiHelper;
020
021public abstract class FileImporter implements Comparable<FileImporter>, LayerChangeListener {
022
023    public final ExtensionFileFilter filter;
024
025    private boolean enabled;
026
027    public FileImporter(ExtensionFileFilter filter) {
028        this.filter = filter;
029        this.enabled = true;
030    }
031
032    public boolean acceptFile(File pathname) {
033        return filter.acceptName(pathname.getName());
034    }
035
036    /**
037     * A batch importer is a file importer that prefers to read multiple files at the same time.
038     */
039    public boolean isBatchImporter() {
040        return false;
041    }
042
043    /**
044     * Needs to be implemented if isBatchImporter() returns false.
045     */
046    public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
047        throw new IOException(tr("Could not import ''{0}''.", file.getName()));
048    }
049
050    /**
051     * Needs to be implemented if isBatchImporter() returns true.
052     */
053    public void importData(List<File> files, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
054        throw new IOException(tr("Could not import files."));
055    }
056
057    /**
058     * Wrapper to give meaningful output if things go wrong.
059     * @return true if data import was successful
060     */
061    public boolean importDataHandleExceptions(File f, ProgressMonitor progressMonitor) {
062        try {
063            Main.info("Open file: " + f.getAbsolutePath() + " (" + f.length() + " bytes)");
064            importData(f, progressMonitor);
065            return true;
066        } catch (IllegalDataException e) {
067            Throwable cause = e.getCause();
068            if (cause instanceof ImportCancelException) {
069                displayCancel(cause);
070            } else {
071                displayError(f, e);
072            }
073            return false;
074        } catch (Exception e) {
075            displayError(f, e);
076            return false;
077        }
078    }
079
080    private static void displayError(File f, Exception e) {
081        Main.error(e);
082        HelpAwareOptionPane.showMessageDialogInEDT(
083                Main.parent,
084                tr("<html>Could not read file ''{0}''.<br>Error is:<br>{1}</html>", f.getName(), e.getMessage()),
085                tr("Error"),
086                JOptionPane.ERROR_MESSAGE, null
087        );
088    }
089
090    private static void displayCancel(final Throwable t) {
091        GuiHelper.runInEDTAndWait(new Runnable() {
092            @Override
093            public void run() {
094                Notification note = new Notification(t.getMessage());
095                note.setIcon(JOptionPane.INFORMATION_MESSAGE);
096                note.setDuration(Notification.TIME_SHORT);
097                note.show();
098            }
099        });
100    }
101
102    public boolean importDataHandleExceptions(List<File> files, ProgressMonitor progressMonitor) {
103        try {
104            Main.info("Open "+files.size()+" files");
105            importData(files, progressMonitor);
106            return true;
107        } catch (Exception e) {
108            Main.error(e);
109            HelpAwareOptionPane.showMessageDialogInEDT(
110                    Main.parent,
111                    tr("<html>Could not read files.<br>Error is:<br>{0}</html>", e.getMessage()),
112                    tr("Error"),
113                    JOptionPane.ERROR_MESSAGE, null
114            );
115            return false;
116        }
117    }
118
119    /**
120     * If multiple files (with multiple file formats) are selected,
121     * they are opened in the order of their priorities.
122     * Highest priority comes first.
123     */
124    public double getPriority() {
125        return 0;
126    }
127
128    @Override
129    public int compareTo(FileImporter other) {
130        return Double.compare(this.getPriority(), other.getPriority());
131    }
132
133    /**
134     * Returns the enabled state of this {@code FileImporter}. When enabled, it is listed and usable in "File-&gt;Open" dialog.
135     * @return true if this {@code FileImporter} is enabled
136     * @since 5459
137     */
138    public final boolean isEnabled() {
139        return enabled;
140    }
141
142    /**
143     * Sets the enabled state of the {@code FileImporter}. When enabled, it is listed and usable in "File-&gt;Open" dialog.
144     * @param enabled true to enable this {@code FileImporter}, false to disable it
145     * @since 5459
146     */
147    public final void setEnabled(boolean enabled) {
148        this.enabled = enabled;
149    }
150
151    @Override
152    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
153        // To be overriden by subclasses if their enabled state depends of the active layer nature
154    }
155
156    @Override
157    public void layerAdded(Layer newLayer) {
158        // To be overriden by subclasses if needed
159    }
160
161    @Override
162    public void layerRemoved(Layer oldLayer) {
163        // To be overriden by subclasses if needed
164    }
165}