XJFileChooser.java
001 /*
002  * Copyright (c) 1998-2009, The University of Sheffield.
003  * Copyright (c) 2009-2009, Ontotext, Bulgaria.
004  *
005  * This file is part of GATE (see http://gate.ac.uk/), and is free
006  * software, licenced under the GNU Library General Public License,
007  * Version 2, June 1991 (in the distribution as file licence.html,
008  * and also available at http://gate.ac.uk/gate/licence.html).
009  *
010  * Thomas Heitz - 15/09/2009
011  *
012  * $Id:$
013  *
014  */
015 
016 package gate.swing;
017 
018 import gate.Gate;
019 import gate.gui.MainFrame;
020 
021 import java.awt.Component;
022 import java.awt.HeadlessException;
023 import java.io.File;
024 import java.util.Map;
025 
026 import javax.swing.JFileChooser;
027 import javax.swing.event.AncestorEvent;
028 import javax.swing.event.AncestorListener;
029 import javax.swing.filechooser.FileFilter;
030 
031 /**
032  * Extends {@link javax.swing.JFileChooser} to make sure the shared
033  {@link MainFrame} instance is used as a parent when no parent is specified.
034  <br><br>
035  * Remember the last path used for each resource type.
036  * The path is saved when the user confirm the dialog.
037  * The resource name must be set with the method {@link #setResource(String)}.
038  * Use {@link #setSelectedFile(java.io.File)} to preselect a different file
039  * or use {@link #setFileName(String)} to use a different file name but the
040  * saved directory.
041  <br><br>
042  * Resource paths are saved in the user config file.
043  */
044 @SuppressWarnings("serial")
045 public class XJFileChooser extends JFileChooser {
046   /** key used when saving the file location to be retrieved later */
047   private String resource;
048   /** file name used instead of the one saved in the preferences */
049   private String fileName;
050   /** set to true when setSelectedFile has been used */
051   private boolean isFileSelected = false;
052   /** map for (resource name -> path) saved in the user config file */
053   private Map<String, String> locations;
054 
055   public XJFileChooser() {
056     addAncestorListener(new AncestorListener() {
057       @Override
058       public void ancestorAdded(AncestorEvent event) { /* do nothing */ }
059       @Override
060       public void ancestorRemoved(AncestorEvent event) {
061         // reinitialise fields when the file chooser is hidden
062         resource = null;
063         fileName = null;
064         isFileSelected = false;
065         resetChoosableFileFilters();
066       }
067       @Override
068       public void ancestorMoved(AncestorEvent event) { /* do nothing */ }
069     });
070     locations = getLocations();
071   }
072 
073   /**
074    * Overridden to make sure the shared MainFrame instance is used as
075    * a parent when no parent is specified
076    */
077   @Override
078   public int showDialog(Component parent, String approveButtonText)
079   throws HeadlessException {
080     setSelectedFileFromPreferences();
081     return super.showDialog((parent != null? parent :
082       (MainFrame.getFileChooser() != null? MainFrame.getInstance() :
083         null, approveButtonText);
084   }
085 
086   /**
087    * If possible, select the last directory/file used for the resource
088    * otherwise use the last file chooser selection directory or if null
089    * use the user home directory.
090    */
091   public void setSelectedFileFromPreferences() {
092     String lastUsedPath = getLocationForResource(resource);
093     File file;
094     String specifiedDefaultDir =
095       System.getProperty("gate.user.filechooser.defaultdir");
096     if (isFileSelected) {
097       // a file has already been selected so do not use the saved one
098       return
099     else if (lastUsedPath != null && fileName != null) {
100       file = new File(lastUsedPath);
101       if (!file.isDirectory()) {
102         file = file.getParentFile();
103       }
104       file = new File(file, fileName);
105     else if (lastUsedPath != null) {
106       file = new File(lastUsedPath);
107     else if (fileName != null) {
108       // if the property for setting a default directory has been set,
109       // use that for finding the file, otherwise use whatever the
110       // user home directory is on this operating system.
111       if(specifiedDefaultDir != null) {
112         file = new File(specifiedDefaultDir, fileName);
113       else {
114         file = new File(System.getProperty("user.home"), fileName);
115       }
116     else {
117       // if the property for setting a default directory has been set,
118       // let the filechooser know, otherwise just do whatever the
119       // default behavior is.
120       if(specifiedDefaultDir != null) {
121         this.setCurrentDirectory(new File(specifiedDefaultDir));
122       }
123       return;
124     }
125     setSelectedFile(file);
126     ensureFileIsVisible(file);
127   }
128 
129   public String getLocationForResource(String resource) {
130     locations = getLocations();
131     return (resource == nullnull : locations.get(resource);
132   }
133 
134   /**
135    * Useful to modify the locations used by this file chooser.
136    @return a map of resource (name * file location)
137    @see #setLocations(java.util.Map)
138    */
139   public Map<String, String> getLocations() {
140     return Gate.getUserConfig().getMap(XJFileChooser.class.getName());
141   }
142 
143   /**
144    * Useful to modify the locations used by this file chooser.
145    @param locations a map of (resource name * file location)
146    @see #getLocations()
147    */
148   public void setLocations(Map<String, String> locations) {
149     Gate.getUserConfig().put(XJFileChooser.class.getName(), locations);
150   }
151 
152   /**
153    * Set the file name to be used instead of the one saved in the preferences.
154    @param fileName file name
155    */
156   public void setFileName(String fileName) {
157     this.fileName = fileName;
158   }
159 
160   /** overriden to first save the location of the file chooser
161    *  for the current resource. */
162   @Override
163   public void approveSelection() {
164     if (resource != null && getSelectedFile() != null) {
165       //String filePath = getSelectedFile().getCanonicalPath();
166       String filePath = getSelectedFile().getAbsolutePath();
167       locations.put(resource, filePath);
168       setLocations(locations);
169     }
170     super.approveSelection();
171   }
172 
173   /**
174    * Set the resource to remember the path. Must be set before to call
175    {@link #showDialog}.
176    @param resource name of the resource
177    */
178   public void setResource(String resource) {
179     this.resource = resource;
180   }
181 
182   /**
183    * Get the resource associated to this file chooser.
184    @return name of the resource
185    */
186   public String getResource() {
187     return resource;
188   }
189 
190   /** Overriden to test first if the file exists */
191   @Override
192   public void ensureFileIsVisible(File f) {
193     if(f != null && f.exists()) super.ensureFileIsVisible(f);
194   }
195 
196   /** Overriden to test first if the file exists */
197   @Override
198   public void setSelectedFile(File file) {
199     if(file != null){
200       if(file.exists() ||
201          (file.getParentFile() != null && file.getParentFile().exists())){
202         super.setSelectedFile(file);
203       }
204       isFileSelected = true;
205     }
206   }
207 
208   /** overriden to add a filter only if not already present */
209   @Override
210   public void addChoosableFileFilter(FileFilter filterToAdd) {
211     for (FileFilter filter : getChoosableFileFilters()) {
212       if (filter.getDescription().equals(filterToAdd.getDescription())) {
213         setFileFilter(filter);
214         return;
215       }
216     }
217     super.addChoosableFileFilter(filterToAdd);
218   }
219 }