001/** 002 * Please feel free to use any fragment of the code in this file that you need in your own 003 * work. As far as I am concerned, it's in the public domain. No permission is necessary 004 * or required. Credit is always appreciated if you use a large chunk or base a 005 * significant product on one of my examples, but that's not required either. 006 * 007 * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 008 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 009 * PURPOSE. 010 * 011 * --- Joseph A. Huwaldt 012 */ 013package jahuwaldt.io; 014 015import java.io.File; 016import java.io.FileFilter; 017import java.io.FilenameFilter; 018import java.util.List; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.Iterator; 022import static java.util.Objects.isNull; 023import static java.util.Objects.nonNull; 024import static java.util.Objects.requireNonNull; 025import java.util.StringTokenizer; 026 027/** 028 * A convenience implementation of FilenameFilter and FileFilter that filters out all 029 * files except for those type extensions that it knows about. 030 * 031 * Extensions are of the type ".foo", which is typically found on Windows and Unix boxes, 032 * but not on the Macintosh prior to OS X. Case is ignored. 033 * 034 * <p> Modified by: Joseph A. Huwaldt </p> 035 * 036 * @author Joseph A. Huwaldt, Date: June 18, 2004 037 * @version September 16, 2016 038 */ 039public class ExtFilenameFilter implements FilenameFilter, FileFilter { 040 // This class now requires Java 1.7 or later! 041 042 private List<String> filters = null; 043 044 private HashMap<String, ExtFilenameFilter> nameFilters = null; 045 046 private String description = null; 047 048 private String fullDescription = null; 049 050 private boolean useExtensionsInDescription = true; 051 052 /** 053 * Creates a filename filter. If no filters are added, then all files are accepted. 054 * 055 * @see #addExtension(java.lang.String) 056 */ 057 public ExtFilenameFilter() { 058 this((String)null, (String)null); 059 } 060 061 /** 062 * Creates a filename filter that accepts files with the given extension. Example: new 063 * ExtFilenameFilter("jpg"); 064 * 065 * @param extension The file name extension to use for this filter. Null extensions 066 * are ignored. 067 * @see #addExtension(java.lang.String) 068 */ 069 public ExtFilenameFilter(String extension) { 070 this(extension, null); 071 } 072 073 /** 074 * Creates a file filter that accepts the given file type. Example: 075 * <code>new ExtFilenameFilter("jpg", "JPEG Image Images");</code> 076 * <p> 077 * Note that the "." before the extension is not needed, but it is fine if it is 078 * there.</p> 079 * 080 * @param extension The file name extension to use for this filter. Null extensions 081 * are ignored. 082 * @param description A description of the file type of this filter. Null is fine. 083 * @see #addExtension(java.lang.String) 084 */ 085 public ExtFilenameFilter(String extension, String description) { 086 this(new String[]{extension}, description); 087 } 088 089 /** 090 * Creates a file filter from the given string array. Example: 091 * <code>new ExtFilenameFilter(String {"gif", "jpg"});</code> 092 * <p> 093 * Note that the "." before the extension is not needed, but it is fine if it is 094 * there.</p> 095 * 096 * @param filters An array of String objects where each entry is a file name extension 097 * to be included in this filter. May not be null. 098 * @see #addExtension(java.lang.String) 099 */ 100 public ExtFilenameFilter(String... filters) { 101 this(requireNonNull(filters), null); 102 } 103 104 /** 105 * Creates a file filter from the given string array and description. Example: 106 * <code>new ExtFilenameFilter(String {"gif", "jpg"}, "Gif and JPG Images");</code> 107 * <p> 108 * Note that the "." before the extension is not needed, but it is fine if it is 109 * there.</p> 110 * 111 * @param filters An array of String objects where each entry is a file name 112 * extension to be included in this filter. Any null members of the 113 * array are ignored. The array itself may not be null. 114 * @param description The description of the extensions in this filter set. Null is 115 * fine. 116 * @see #addExtension(java.lang.String) 117 */ 118 public ExtFilenameFilter(String[] filters, String description) { 119 requireNonNull(filters); 120 this.filters = new ArrayList<>(); 121 for (String filter : filters) { 122 // add filters one by one 123 if (nonNull(filter)) 124 addExtension(filter); 125 } 126 setDescription(description); 127 nameFilters = new HashMap<>(4); 128 } 129 130 /** 131 * Return true if this file should be shown , false if it should not. 132 * 133 * @param f The file that is to be tested for compatibility with this filter. 134 */ 135 @Override 136 public boolean accept(File f) { 137 if (nonNull(f)) { 138 if (f.isDirectory()) 139 return true; 140 141 String name = f.getName().toLowerCase(); 142 if (nonNull(nameFilters.get(name))) 143 return true; 144 145 return extensionMatch(name); 146 } 147 return false; 148 } 149 150 /** 151 * Return true if this file should be included in a file list, false if it shouldn't. 152 * 153 * @param dir The directory in which the file was found. 154 * @param name The name of the file. 155 */ 156 @Override 157 public boolean accept(File dir, String name) { 158 if (nonNull(dir) && nonNull(name)) { 159 160 if (nonNull(nameFilters.get(name))) 161 return true; 162 163 return extensionMatch(name); 164 } 165 return false; 166 } 167 168 /** 169 * Tests to see if the specified name ends with any of the allow extensions. 170 * 171 * @param fileName The file name to test. 172 * @return <code>true</code> if the file name ends with any of the allowed extensions, 173 * <code>false</code> if it does not. If there are no extensions defined, this 174 * will always return true (all files will match). 175 */ 176 private boolean extensionMatch(String fileName) { 177 if (filters.isEmpty()) 178 return true; 179 180 for (String ext : filters) { 181 if (getExtension(fileName).equals(ext)) 182 return true; 183 } 184 185 return false; 186 } 187 188 /** 189 * Return the extension portion of the file's name. The extension will always be 190 * returned in lower case and without the ".". 191 * 192 * @param name The file name for which the extension is to be returned. May not be 193 * null. 194 * @return The extension portion of the file's name without the "." or "" if there is 195 * no extension. 196 * @see #getExtension(java.io.File) 197 */ 198 public static String getExtension(String name) { 199 int i = name.lastIndexOf('.'); 200 if (i > 0 && i < name.length() - 1) 201 return name.substring(i + 1).toLowerCase().trim(); 202 return ""; 203 } 204 205 /** 206 * Return the extension portion of the file's name. The extension will always be 207 * returned in lower case and without the ".". 208 * 209 * @param f The file object for which the extension is to be returned. May not be 210 * null. 211 * @return The extension portion of the file's name without the "." or "" if there is 212 * no extension. 213 * @see #getExtension(java.lang.String) 214 */ 215 public static String getExtension(File f) { 216 requireNonNull(f, "f == null"); 217 return getExtension(f.getName()); 218 } 219 220 /** 221 * Adds a file name "dot" extension to filter against. 222 * <p> 223 * For example: the following code will create a filter that filters out all files 224 * except those that end in ".jpg" and ".tif": 225 * <pre> 226 * ExtFilenameFilter filter = new ExtFilenameFilter(); filter.addExtension("jpg"); 227 * filter.addExtension("tif"); 228 * </pre></p> 229 * <p> 230 * Note that the "." before the extension is not needed, but it is fine if it is 231 * there. 232 * </p> 233 * 234 * @param extension The file name extension to be added to this filter. May not be 235 * null. 236 */ 237 public final void addExtension(String extension) { 238 requireNonNull(extension, "extension == null"); 239 240 if (!extension.equals("")) { 241 // Make sure that the extension never starts with a ".". 242 while (extension.startsWith(".")) 243 extension = extension.substring(1); 244 245 // Store the extension in our database of extensions. 246 filters.add(extension.toLowerCase()); 247 } 248 249 fullDescription = null; 250 } 251 252 /** 253 * Adds a full filename to filter against. 254 * <p> 255 * For example: the following code will create a filter that filters out all files 256 * except those that end in ".jpg" and ".tif" or have the name "foo.bar": 257 * <pre> 258 * ExtFilenameFilter filter = new ExtFilenameFilter(); 259 * filter.addExtension("jpg"); 260 * filter.addExtension("tif"); 261 * filter.addFileName("foo.bar"); 262 * </pre></p> 263 * 264 * @param fileName A full file name to add to this filter for filtering against. May 265 * not be null. 266 */ 267 public void addFilename(String fileName) { 268 requireNonNull(fileName, "fileName == null"); 269 if (!fileName.equals("")) { 270 nameFilters.put(fileName.toLowerCase(), this); 271 } 272 } 273 274 /** 275 * Adds a list of extensions parsed from a comma, space or tab delimited list. 276 * <p> 277 * For example, the following will create a filter that filters out all files except 278 * those that end in ".jpg" and ".png": 279 * <pre> 280 * ExtFilenameFilter filter = new ExtFilenameFilter(); 281 * filter.addExtensions("jpg,png,gif"); 282 * </pre></p> 283 * 284 * @param extensionList A delimited list of extensions to add to the filter. May not 285 * be null. 286 */ 287 public void addExtensions(String extensionList) { 288 requireNonNull(extensionList, "extensionList == null"); 289 StringTokenizer tokenizer = new StringTokenizer(extensionList, ", \t"); 290 while (tokenizer.hasMoreTokens()) { 291 addExtension(tokenizer.nextToken()); 292 } 293 } 294 295 /** 296 * Returns the human readable description of this filter. For example: "JPEG and GIF 297 * Image Files (*.jpg, *.gif)" 298 * 299 * @return The description of this filter. 300 * @see #setDescription(java.lang.String) 301 * @see #setExtensionListInDescription(boolean) 302 * @see #isExtensionListInDescription() 303 */ 304 public String getDescription() { 305 if (isNull(fullDescription)) { 306 if (isNull(description) || isExtensionListInDescription()) { 307 if (nonNull(description)) 308 fullDescription = description; 309 fullDescription += " ("; 310 311 // build the description from the extension list 312 Iterator<String> extensions = filters.iterator(); 313 if (nonNull(extensions)) { 314 fullDescription += extensions.next().substring(1); 315 while (extensions.hasNext()) 316 fullDescription += ", " + extensions.next().substring(1); 317 } 318 fullDescription += ")"; 319 320 } else { 321 fullDescription = description; 322 } 323 } 324 return fullDescription; 325 } 326 327 /** 328 * Sets the human readable description of this filter. For example: 329 * filter.setDescription("GIF and JPEG Images"); 330 * 331 * @param description The description to be used for this filter. Null is fine. 332 * @see #setDescription(java.lang.String) 333 * @see #setExtensionListInDescription(boolean) 334 * @see #isExtensionListInDescription() 335 */ 336 public final void setDescription(String description) { 337 this.description = description; 338 fullDescription = null; 339 } 340 341 /** 342 * Determines whether the extension list (.jpg,.gif, etc) should show up in the human 343 * readable description. 344 * <p> 345 * Only relevant if a description was provided in the constructor or using 346 * <code>setDescription()</code></p> 347 * 348 * @param useExtInDescription Set to true to use the extension list in the description 349 * of this filter. 350 * @see #getDescription() 351 * @see #setDescription(java.lang.String) 352 * @see #isExtensionListInDescription() 353 */ 354 public void setExtensionListInDescription(boolean useExtInDescription) { 355 useExtensionsInDescription = useExtInDescription; 356 fullDescription = null; 357 } 358 359 /** 360 * Returns whether the extension list (.jpg,.gif, etc) should show up in the human 361 * readable description. 362 * </p> 363 * Only relevant if a description was provided in the constructor or using 364 * <code>setDescription()</code></p> 365 * 366 * @return true if the extension list is a part of the human readable description. 367 * @see #getDescription() 368 * @see #setDescription(java.lang.String) 369 * @see #setExtensionListInDescription(boolean) 370 */ 371 public boolean isExtensionListInDescription() { 372 return useExtensionsInDescription; 373 } 374 375}