001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.io;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.io.File;
007 import java.io.IOException;
008 import java.util.ArrayList;
009 import java.util.Arrays;
010 import java.util.HashSet;
011 import java.util.List;
012 import java.util.Set;
013
014 import org.openstreetmap.josm.actions.ExtensionFileFilter;
015 import org.openstreetmap.josm.gui.layer.GpxLayer;
016 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
017 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
018
019 /**
020 * File importer allowing to import geottaged images (*.jpg files).
021 *
022 */
023 public class JpgImporter extends FileImporter {
024 private GpxLayer gpx;
025
026 /**
027 * The default file filter (only *.jpg files).
028 */
029 public static final ExtensionFileFilter FILE_FILTER = new ExtensionFileFilter(
030 "jpg", "jpg", tr("Image Files") + " (*.jpg)");
031
032 /**
033 * An alternate file filter that also includes folders.
034 * @since 5438
035 */
036 public static final ExtensionFileFilter FILE_FILTER_WITH_FOLDERS = new ExtensionFileFilter(
037 "jpg", "jpg", tr("Image Files") + " (*.jpg, "+ tr("folder")+")");
038
039 /**
040 * Constructs a new {@code JpgImporter}.
041 */
042 public JpgImporter() {
043 this(false);
044 }
045
046 /**
047 * Constructs a new {@code JpgImporter} with folders selection, if wanted.
048 * @param includeFolders If true, includes folders in the file filter
049 * @since 5438
050 */
051 public JpgImporter(boolean includeFolders) {
052 super(includeFolders ? FILE_FILTER_WITH_FOLDERS : FILE_FILTER);
053 }
054
055 /**
056 * Constructs a new {@code JpgImporter} for the given GPX layer. Folders selection is allowed.
057 * @param gpx The GPX layer
058 */
059 public JpgImporter(GpxLayer gpx) {
060 this(true);
061 this.gpx = gpx;
062 }
063
064 @Override
065 public boolean acceptFile(File pathname) {
066 return super.acceptFile(pathname) || pathname.isDirectory();
067 }
068
069 @Override
070 public void importData(List<File> sel, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
071 progressMonitor.beginTask(tr("Looking for image files"), 1);
072 try {
073 List<File> files = new ArrayList<File>();
074 Set<String> visitedDirs = new HashSet<String>();
075 addRecursiveFiles(files, visitedDirs, sel, progressMonitor.createSubTaskMonitor(1, true));
076
077 if (progressMonitor.isCanceled())
078 return;
079
080 if (files.isEmpty())
081 throw new IOException(tr("No image files found."));
082
083 GeoImageLayer.create(files, gpx);
084 } finally {
085 progressMonitor.finishTask();
086 }
087 }
088
089 private void addRecursiveFiles(List<File> files, Set<String> visitedDirs, List<File> sel, ProgressMonitor progressMonitor) throws IOException {
090
091 if (progressMonitor.isCanceled())
092 return;
093
094 progressMonitor.beginTask(null, sel.size());
095 try {
096 for (File f : sel) {
097 if (f.isDirectory()) {
098 if (visitedDirs.add(f.getCanonicalPath())) { // Do not loop over symlinks
099 File[] dirFiles = f.listFiles(); // Can be null for some strange directories (like lost+found)
100 if (dirFiles != null) {
101 addRecursiveFiles(files, visitedDirs, Arrays.asList(dirFiles), progressMonitor.createSubTaskMonitor(1, true));
102 }
103 } else {
104 progressMonitor.worked(1);
105 }
106 } else {
107 if (f.getName().toLowerCase().endsWith(".jpg")) {
108 files.add(f);
109 }
110 progressMonitor.worked(1);
111 }
112 }
113 } finally {
114 progressMonitor.finishTask();
115 }
116 }
117
118 @Override
119 public boolean isBatchImporter() {
120 return true;
121 }
122
123 /**
124 * Needs to be the last, to avoid problems.
125 */
126 @Override
127 public double getPriority() {
128 return -1000;
129 }
130 }