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