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.gui.MainFrame;
019 import gate.Gate;
020 
021 import javax.swing.JFileChooser;
022 import javax.swing.event.AncestorListener;
023 import javax.swing.event.AncestorEvent;
024 import javax.swing.filechooser.FileFilter;
025 import java.awt.Component;
026 import java.awt.HeadlessException;
027 import java.io.File;
028 import java.io.IOException;
029 import java.util.Map;
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 public class XJFileChooser extends JFileChooser {
045   /** key used when saving the file location to be retrieved later */
046   private String resource;
047   /** file name used instead of the one saved in the preferences */
048   private String fileName;
049   /** set to true when setSelectedFile has been used */
050   private boolean isFileSelected = false;
051   /** map for (resource name -> path) saved in the user config file */
052   private Map<String, String> locations;
053 
054   public XJFileChooser() {
055     addAncestorListener(new AncestorListener() {
056       public void ancestorAdded(AncestorEvent event) { /* do nothing */ }
057       public void ancestorRemoved(AncestorEvent event) {
058         // reinitialise fields when the file chooser is hidden
059         resource = null;
060         fileName = null;
061         isFileSelected = false;
062         resetChoosableFileFilters();
063       }
064       public void ancestorMoved(AncestorEvent event) { /* do nothing */ }
065     });
066   }
067 
068   /**
069    * Overridden to make sure the shared MainFrame instance is used as
070    * a parent when no parent is specified
071    */
072   public int showDialog(Component parent, String approveButtonText)
073   throws HeadlessException {
074     setSelectedFileFromPreferences();
075     return super.showDialog((parent != null? parent :
076       (MainFrame.getFileChooser() != null? MainFrame.getInstance() :
077         null, approveButtonText);
078   }
079 
080   /**
081    * If possible, select the last directory/file used for the resource
082    * otherwise use the last file chooser selection directory or if null
083    * use the user home directory.
084    */
085   public void setSelectedFileFromPreferences() {
086     String lastUsedPath = getLocationForResource(resource);
087     File file;
088     String specifiedDefaultDir =
089       System.getProperty("gate.user.filechooser.defaultdir");
090     if (isFileSelected) {
091       // a file has already been selected so do not use the saved one
092       return
093     else if (lastUsedPath != null && fileName != null) {
094       file = new File(lastUsedPath);
095       if (!file.isDirectory()) {
096         file = file.getParentFile();
097       }
098       file = new File(file, fileName);
099     else if (lastUsedPath != null) {
100       file = new File(lastUsedPath);
101     else if (fileName != null) {
102       // if the property for setting a default directory has been set,
103       // use that for finding the file, otherwise use whatever the
104       // user home directory is on this operating system.
105       if(specifiedDefaultDir != null) {
106         file = new File(specifiedDefaultDir, fileName);
107       else {
108         file = new File(System.getProperty("user.home"), fileName);
109       }
110     else {
111       // if the property for setting a default directory has been set,
112       // let the filechooser know, otherwise just do whatever the
113       // default behavior is.
114       if(specifiedDefaultDir != null) {
115         this.setCurrentDirectory(new File(specifiedDefaultDir));
116       }
117       return;
118     }
119     setSelectedFile(file);
120     ensureFileIsVisible(file);
121   }
122 
123   public String getLocationForResource(String resource) {
124     locations = getLocations();
125     return (resource == nullnull : locations.get(resource);
126   }
127 
128   /**
129    * Useful to modify the locations used by this file chooser.
130    @return a map of resource (name * file location)
131    @see #setLocations(java.util.Map)
132    */
133   public Map<String, String> getLocations() {
134     return Gate.getUserConfig().getMap(XJFileChooser.class.getName());
135   }
136 
137   /**
138    * Useful to modify the locations used by this file chooser.
139    @param locations a map of (resource name * file location)
140    @see #getLocations()
141    */
142   public void setLocations(Map<String, String> locations) {
143     Gate.getUserConfig().put(XJFileChooser.class.getName(), locations);
144   }
145 
146   /**
147    * Set the file name to be used instead of the one saved in the preferences.
148    @param fileName file name
149    */
150   public void setFileName(String fileName) {
151     this.fileName = fileName;
152   }
153 
154   /** overriden to first save the location of the file chooser
155    *  for the current resource. */
156   public void approveSelection() {
157     if (resource != null && getSelectedFile() != null) {
158       try {
159         String filePath = getSelectedFile().getCanonicalPath();
160         locations.put(resource, filePath);
161         setLocations(locations);
162       catch (IOException e) {
163         e.printStackTrace();
164       }
165     }
166     super.approveSelection();
167   }
168 
169   /**
170    * Set the resource to remember the path. Must be set before to call
171    {@link #showDialog}.
172    @param resource name of the resource
173    */
174   public void setResource(String resource) {
175     this.resource = resource;
176   }
177 
178   /**
179    * Get the resource associated to this file chooser.
180    @return name of the resource
181    */
182   public String getResource() {
183     return resource;
184   }
185 
186   /** Overriden to test first if the file exists */
187   public void ensureFileIsVisible(File f) {
188     if(f != null && f.exists()) super.ensureFileIsVisible(f);
189   }
190 
191   /** Overriden to test first if the file exists */
192   public void setSelectedFile(File file) {
193     if(file != null){
194       if(file.exists() ||
195          (file.getParentFile() != null && file.getParentFile().exists())){
196         super.setSelectedFile(file);
197       }
198       isFileSelected = true;
199     }
200   }
201 
202   /** overriden to add a filter only if not already present */
203   public void addChoosableFileFilter(FileFilter filterToAdd) {
204     for (FileFilter filter : getChoosableFileFilters()) {
205       if (filter.getDescription().equals(filterToAdd.getDescription())) {
206         setFileFilter(filter);
207         return;
208       }
209     }
210     super.addChoosableFileFilter(filterToAdd);
211   }
212 }