| 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