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