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 }