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 | */
|
---|
16 | package org.tp23.gui.widget;
|
---|
17 |
|
---|
18 | import java.beans.PropertyChangeEvent;
|
---|
19 | import java.beans.PropertyChangeListener;
|
---|
20 | import java.io.File;
|
---|
21 |
|
---|
22 | import javax.swing.JFileChooser;
|
---|
23 | import javax.swing.filechooser.FileFilter;
|
---|
24 | import 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 | */
|
---|
60 | public 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);
|
---|
100 | }
|
---|
101 | }
|
---|
102 |
|
---|
103 |
|
---|
104 | /**
|
---|
105 | * Sets the default directory.
|
---|
106 | * @param dir the current directory to point to
|
---|
107 | * @todo Implement this javax.swing.JFileChooser method
|
---|
108 | */
|
---|
109 | public void setDefaultDirectory(File dir) {
|
---|
110 | if(dir==null)return;// called by the default consructor
|
---|
111 | if(createMode){
|
---|
112 | if(desiredName == null)desiredName = dir.getName();
|
---|
113 | File selected = determineCreateDir(dir);
|
---|
114 | super.setCurrentDirectory(selected.getParentFile());
|
---|
115 | setSelectedFile(selected);
|
---|
116 | }else{
|
---|
117 | super.setCurrentDirectory(determineExistingDir(dir));
|
---|
118 | }
|
---|
119 | }
|
---|
120 |
|
---|
121 |
|
---|
122 |
|
---|
123 | private File determineExistingDir(File defaultDir){
|
---|
124 | if(defaultDir.exists())return defaultDir;
|
---|
125 | FileSystemView fsv = this.getFileSystemView();
|
---|
126 | File validParent = getFSVParent(fsv,defaultDir);
|
---|
127 | if(validParent!=null) {
|
---|
128 | return validParent;
|
---|
129 | }
|
---|
130 | else {
|
---|
131 | return fsv.getHomeDirectory();
|
---|
132 | }
|
---|
133 | }
|
---|
134 | /**
|
---|
135 | * Select a base path for the default even if it does not exist. The order of preference is as follows
|
---|
136 | * if the directory exists use it
|
---|
137 | * if the parent does not exist try finding the next parent
|
---|
138 | * if the next parent is a root directory e.g. / or C:\ use the users home directory
|
---|
139 | * @param defaultDir File
|
---|
140 | * @return File
|
---|
141 | */
|
---|
142 | private File determineCreateDir(File defaultDir){
|
---|
143 | if(defaultDir.exists())return defaultDir;
|
---|
144 | FileSystemView fsv = this.getFileSystemView();
|
---|
145 | String dirName = defaultDir.getName();
|
---|
146 | File validParent = getFSVParent(fsv,defaultDir);
|
---|
147 | if(validParent!=null){
|
---|
148 | return new File(validParent, dirName);
|
---|
149 | }
|
---|
150 | else {
|
---|
151 | return new File(fsv.getHomeDirectory(), dirName);
|
---|
152 | }
|
---|
153 | }
|
---|
154 | /**
|
---|
155 | * Step back up trying to find a parent if none if found return null.
|
---|
156 | * null can be found if the path starts e:\ and e: does not exist
|
---|
157 | * @param fsv FileSystemView
|
---|
158 | * @param dir File
|
---|
159 | * @return File
|
---|
160 | */
|
---|
161 | private File getFSVParent(FileSystemView fsv,File dir){
|
---|
162 | File parent = dir.getParentFile();
|
---|
163 | if(fsv.isRoot(parent) && !parent.exists()){
|
---|
164 | return null;
|
---|
165 | }
|
---|
166 | if(!parent.exists() || !fsv.isFileSystem(parent)){
|
---|
167 | parent = getFSVParent(fsv,parent);
|
---|
168 | }
|
---|
169 | return parent;
|
---|
170 | }
|
---|
171 |
|
---|
172 | public static void main(String[] args) {
|
---|
173 | DefaultingDirectoryChooser chooser = new DefaultingDirectoryChooser(CREATE_MODE);
|
---|
174 | chooser.setDefaultDirectory(new File("/usr/local/dibble/MyApp"));
|
---|
175 |
|
---|
176 | chooser.showDialog(null,"Select");
|
---|
177 | System.out.println("Selected:"+chooser.getSelectedFile().getAbsolutePath());
|
---|
178 | System.exit(0);
|
---|
179 | }
|
---|
180 | }
|
---|