DefaultingDirectoryChooser.java |
1 /* 2 * Copyright 2005 Paul Hinds 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.tp23.gui.widget; 17 18import java.beans.PropertyChangeEvent; 19import java.beans.PropertyChangeListener; 20import java.io.File; 21 22import javax.swing.JFileChooser; 23import javax.swing.filechooser.FileFilter; 24import javax.swing.filechooser.FileSystemView; 25/** 26 * A file chooser that makes a beter default if the default directory is not available. 27* Basically the default looks for the suggested directory and if it does not find it moves back 28* up the directories. If still nothing is found (for example it may get to My Computer 29* which you can not add file to) the home directory is selected, as in the default file chooser. 30* 31* To use this class call new DefaultingDirectoryChooser(boolean) and immediately call 32* setDefaultDirectory(File) to determine the default. If you don't it behaves like the default JFileChooser 33* Also if you call setCurrentDirectory(File) it will behave like JFileChooser 34* 35* This chooser has two modes CREATE_MODE and EXISTING_MODE. <br/><br/> 36* 37* In existing mode it is assumed the chooser is being used to identify an existing directory 38* the default directory should exist if not the directory shown will be the next existing parent.<br/><br/> 39* 40* In create mode it is 41* assumed that the last directory in the default directory is to be created and may not 42* exist yet. Therefor the default directory displayed is the parent (with suitable defaulting) 43* and the text box will contain the name of the last directory. 44* e.g. if default is C:\Program Files\MyApp C:\Program Files will be displayed and 45* MyApp will be shown in the text box (even if it does not exist yet) If C:\Program Files does not exist 46* C:\ will be shown as with existing mode. 47* Choosing select can lead to the creation of the file. It will not be automatically 48* created that is the responsibility of the client code.<br/> 49* 50* This class uses FileSystemView and will only display folders that return true to fsv.isFileSystem() 51* 52* This class also uses a bit of a hack by in CREATE_MODE it sets the selectables to files and directories 53* although only shows the directories this way a non-existing Directory can be chosen. This is the only way I can 54* get it to work on my Java version but I would not be supprised if it did not work on 55* other versions of the Java API. It also means that setFileSelectionMode() should 56* never be called by clients as it will break this hack. 57 * @author Paul Hinds 58 * @version 1.0 59 */ 60public class DefaultingDirectoryChooser extends JFileChooser{ 61 62 public static final boolean CREATE_MODE = true; 63 public static final boolean EXISTING_MODE = false; 64 65 /** 66 * Determines that the default includes a directory name that is requried 67 * e.g. C:\Program Files\MyApp where even if Program Files does not exist 68 * MyApp should be part of the default even if it does not exist. 69 */ 70 private boolean createMode = false; 71 private File selectedFile = null; 72 private String desiredName = null; 73 74 public DefaultingDirectoryChooser(boolean createMode) { 75 this.createMode=createMode; 76 if(createMode){ 77 setFileSelectionMode(FILES_AND_DIRECTORIES); 78 removeChoosableFileFilter(getAcceptAllFileFilter()); 79 addChoosableFileFilter(new FileFilter(){ 80 public boolean accept(File f) { 81 if(f.exists() && f.isDirectory())return true; 82 if(!f.exists() && getFileSystemView().getParentDirectory(f).isDirectory())return true; 83 return false; 84 } 85 public String getDescription() { 86 return "Directories"; 87 } 88 }); 89 90 addPropertyChangeListener(JFileChooser.DIRECTORY_CHANGED_PROPERTY, new PropertyChangeListener(){ 91 public void propertyChange(PropertyChangeEvent evt) { 92 File directory = (File)evt.getNewValue(); 93 DefaultingDirectoryChooser.this.setCurrentDirectory(new File(directory, "newfolder")); 94 setSelectedFile(new File(directory, desiredName)); 95 } 96 }); 97 } 98 else { 99 setFileSelectionMode(DIRECTORIES_ONLY); 00 } 01 } 02 03 04 /** 05 * Sets the default directory. 06 * @param dir the current directory to point to 07 * @todo Implement this javax.swing.JFileChooser method 08 */ 09 public void setDefaultDirectory(File dir) { 10 if(dir==null)return;// called by the default consructor 11 if(createMode){ 12 if(desiredName == null)desiredName = dir.getName(); 13 File selected = determineCreateDir(dir); 14 super.setCurrentDirectory(selected.getParentFile()); 15 setSelectedFile(selected); 16 }else{ 17 super.setCurrentDirectory(determineExistingDir(dir)); 18 } 19 } 20 21 22 23 private File determineExistingDir(File defaultDir){ 24 if(defaultDir.exists())return defaultDir; 25 FileSystemView fsv = this.getFileSystemView(); 26 File validParent = getFSVParent(fsv,defaultDir); 27 if(validParent!=null) { 28 return validParent; 29 } 30 else { 31 return fsv.getHomeDirectory(); 32 } 33 } 34 /** 35 * Select a base path for the default even if it does not exist. The order of preference is as follows 36 * if the directory exists use it 37 * if the parent does not exist try finding the next parent 38 * if the next parent is a root directory e.g. / or C:\ use the users home directory 39 * @param defaultDir File 40 * @return File 41 */ 42 private File determineCreateDir(File defaultDir){ 43 if(defaultDir.exists())return defaultDir; 44 FileSystemView fsv = this.getFileSystemView(); 45 String dirName = defaultDir.getName(); 46 File validParent = getFSVParent(fsv,defaultDir); 47 if(validParent!=null){ 48 return new File(validParent, dirName); 49 } 50 else { 51 return new File(fsv.getHomeDirectory(), dirName); 52 } 53 } 54 /** 55 * Step back up trying to find a parent if none if found return null. 56 * null can be found if the path starts e:\ and e: does not exist 57 * @param fsv FileSystemView 58 * @param dir File 59 * @return File 60 */ 61 private File getFSVParent(FileSystemView fsv,File dir){ 62 File parent = dir.getParentFile(); 63 if(fsv.isRoot(parent) && !parent.exists()){ 64 return null; 65 } 66 if(!parent.exists() || !fsv.isFileSystem(parent)){ 67 parent = getFSVParent(fsv,parent); 68 } 69 return parent; 70 } 71 72 public static void main(String[] args) { 73 DefaultingDirectoryChooser chooser = new DefaultingDirectoryChooser(CREATE_MODE); 74 chooser.setDefaultDirectory(new File("/usr/local/dibble/MyApp")); 75 76 chooser.showDialog(null,"Select"); 77 System.out.println("Selected:"+chooser.getSelectedFile().getAbsolutePath()); 78 System.exit(0); 79 } 80} 81