001/* A JFileChooser or FileDialog. 002 003 Copyright (c) 2011-2018 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.gui; 028 029import java.awt.Container; 030import java.awt.FileDialog; 031import java.awt.Frame; 032import java.io.File; 033import java.io.IOException; 034 035import javax.swing.JFileChooser; 036 037import ptolemy.util.StringUtilities; 038 039/////////////////////////////////////////////////////////////////// 040//// PtFileChooser 041 042/** 043 * A JFileChooser or FileDialog. 044 * 045 * <p>If {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} returns 046 * true, then a java.awt.FileDialog is used. Otherwise a 047 * javax.swing.JFileChooser is used. In general Mac OS X is the only 048 * platform that where useFileDialog() will return true.</p> 049 * 050 * <p> See {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} for how 051 * to set a runtime Java property to control whether FileDialog or 052 * JFileChooser is used.</p> 053 * 054 * <p> Note that this class should be wrapped in a try/finally block, 055 * otherwise, under Windows, white boxes will appear in the common pane. 056 * See {@link ptolemy.gui.JFileChooserBugFix}. Below is an example: </p> 057 * <pre> 058 * // Swap backgrounds and avoid white boxes in "common places" dialog 059 * JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix(); 060 * Color background = null; 061 * PtFileChooser ptFileChooser; 062 * try { 063 * ptFileChooser = new PtFileChooser(_basicGraphFrame, title, 064 * JFileChooser.OPEN_DIALOG); 065 * ptFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 066 * ptFileChooser.setCurrentDirectory(modelDirectory); 067 * ptFileChooser.addChoosableFileFilter(new DirectoryFilter()); 068 * int returnVal = ptFileChooser.showDialog(_basicGraphFrame, "Export HTML"); 069 * 070 * if (returnVal == JFileChooser.APPROVE_OPTION) { 071 * directory = ptFileChooser.getSelectedFile(); 072 * } 073 * } finally { 074 * try { 075 * if (ptFileChooser != null) { 076 * ptFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); 077 * } 078 * } finally { 079 * jFileChooserBugFix.restoreBackground(background); 080 * } 081 * } 082 * </pre> 083 * 084 * <p>Only a subset of the methods in JFileChooser are declared. 085 * The method names follow the JFileChoose API because that API is more 086 * common.</p> 087 * 088 * @author Christopher Brooks 089 * @version $Id$ 090 * @since Ptolemy II 10.0 091 * @Pt.ProposedRating Red (cxh) 092 * @Pt.AcceptedRating Red (cxh) 093 */ 094@SuppressWarnings("serial") 095public class PtFileChooser extends Container { 096 // java.awt.Container is the common baseclass between 097 // java.awt.FileDialog and javax.swing.JFileChooser 098 // Maybe someday this should extend JFileChooser, but only if the 099 // method implementations make sense when used with a FileDialog. 100 101 /** Construct a PtFileChooser. 102 * 103 * <p>If {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} 104 * returns true, then a java.awt.FileDialog is used. Otherwise a 105 * javax.swing.JFileChooser is used. The effect of the mode 106 * argument varies depending on which type of dialog is used.</p> 107 * 108 * @param parent The parent component. Used with FileDialog, 109 * ignored with JFileChooser. 110 * @param title The title of the dialog 111 * @param mode JFileChooser.OPEN_DIALOG, JFileChooser.SAVE_DIALOG, 112 * or JFileChooser.CUSTOM_DIALOG. CUSTOM_DIALOG is ignored by FileDialog. 113 * OPEN_DIALOG is a good default. 114 */ 115 public PtFileChooser(Frame parent, String title, int mode) { 116 _mode = mode; 117 if (PtGUIUtilities.useFileDialog()) { 118 _useFileDialog = true; 119 if (mode == 2) { 120 mode = FileDialog.LOAD; 121 } 122 _fileDialog = new FileDialog(parent, title, mode); 123 } else { 124 _jFileChooser = new JFileChooser(); 125 _jFileChooser.setDialogTitle(title); 126 _jFileChooser.setDialogType(mode); 127 } 128 } 129 130 /** Set the file name filter for the dialog. 131 * @param filter The FilenameFilter to be used. 132 */ 133 public void addChoosableFileFilter(PtFilenameFilter filter) { 134 if (_useFileDialog) { 135 _fileDialog.setFilenameFilter(filter); 136 } else { 137 _jFileChooser.addChoosableFileFilter(filter); 138 } 139 } 140 141 /** Return the current directory. 142 * @return The current directory. 143 * @see #setCurrentDirectory(File) 144 */ 145 public File getCurrentDirectory() { 146 if (_useFileDialog) { 147 return new File(_fileDialog.getDirectory()); 148 } else { 149 return _jFileChooser.getCurrentDirectory(); 150 } 151 } 152 153 /** Return the selected file as an absolute File (a File that is not relative). 154 * @return the selected file. 155 * @see #setSelectedFile(File) 156 */ 157 public File getSelectedFile() { 158 if (_useFileDialog) { 159 return new File(_fileDialog.getDirectory(), _fileDialog.getFile()); 160 } else { 161 return _jFileChooser.getSelectedFile(); 162 } 163 } 164 165 /** Set the current directory. 166 * If the directory parameter is null, then the value of the "user.dir" 167 * property is used. 168 * @param directory The current directory. 169 * @see #getCurrentDirectory() 170 */ 171 public void setCurrentDirectory(File directory) { 172 boolean fail = false; 173 if (directory != null) { 174 if (_useFileDialog) { 175 try { 176 _fileDialog.setDirectory(directory.getCanonicalPath()); 177 } catch (IOException ex) { 178 fail = true; 179 } 180 } else { 181 _jFileChooser.setCurrentDirectory(directory); 182 } 183 } 184 if (fail || directory == null) { 185 // The default on Windows is to open at user.home, which is 186 // typically an absurd directory inside the O/S installation. 187 // So we use the current directory instead. 188 // This will throw a security exception in an applet. 189 // FIXME: we should support users under applets opening files 190 // on the server. 191 String currentWorkingDirectory = StringUtilities 192 .getProperty("user.dir"); 193 194 if (currentWorkingDirectory != null) { 195 if (_useFileDialog) { 196 _fileDialog.setDirectory(currentWorkingDirectory); 197 } else { 198 _jFileChooser.setCurrentDirectory( 199 new File(currentWorkingDirectory)); 200 } 201 } 202 } 203 } 204 205 /** Set the file selection mode. 206 * 207 * <p>If FileDialog is being used, then 208 * DIRECTORIES_ONLY sets the apple.awt.fileDialogForDirectories parameter. 209 * See <a href="https://developer.apple.com/library/mac/#documentation/Java/Reference/Java_PropertiesRef/Articles/JavaSystemProperties.html">https://developer.apple.com/library/mac/#documentation/Java/Reference/Java_PropertiesRef/Articles/JavaSystemProperties.html</a>.</p> 210 * 211 * <p>If this method is called with 212 * JFileChooser.DIRECTORIES_ONLY, then it should be called again 213 * with JFileChooser.FILES_AND_DIRECTORIES. Typically, the first 214 * call is in a try block and the second is in a finally 215 * block.</p> 216 * 217 * <p> Note that if FileDialog is used, and mode is 218 * DIRECTORIES_ONLY, then this class must have been instantiated 219 * with a mode of FileBrowser.LOAD or JFileChooser.OPEN_DIALOG in 220 * the constructor.</p> 221 222 * @param mode One of JFileChooser.FILES_ONLY, JFileChooser.DIRECTORIES_ONLY or 223 * JFileChooser.FILES_AND_DIRECTORIES. 224 */ 225 public void setFileSelectionMode(int mode) { 226 if (_useFileDialog) { 227 if (mode == JFileChooser.DIRECTORIES_ONLY) { 228 if (_mode != 0) { 229 if (!_printedDirectoryWarning) { 230 _printedDirectoryWarning = true; 231 System.out.println( 232 "Warning: The PtFileChooser was instantiated with " 233 + "a mode other than 0, but setFileSelectionMode(DIRECTORIES_ONLY) " 234 + "was called. This is likely to not work."); 235 } 236 } 237 // Mac Specific: allow the user to select a directory. 238 // Note that apple.awt.fileDialogForDirectories only 239 // works with FileDialog.LOAD, not FileDialog.SAVE. 240 // See 241 // https://developer.apple.com/library/mac/#documentation/Java/Reference/Java_PropertiesRef/Articles/JavaSystemProperties.html 242 System.setProperty("apple.awt.fileDialogForDirectories", 243 "true"); 244 } else { 245 System.setProperty("apple.awt.fileDialogForDirectories", 246 "false"); 247 } 248 } else { 249 _jFileChooser.setFileSelectionMode(mode); 250 } 251 } 252 253 /** Set the selected file. 254 * @param file The file to be selected 255 * @see #getSelectedFile() 256 */ 257 public void setSelectedFile(File file) { 258 if (_useFileDialog) { 259 _fileDialog.setFile(file.getName()); 260 } else { 261 _jFileChooser.setSelectedFile(file); 262 } 263 } 264 265 /** Show the dialog. 266 * @param parent Ignored with FileDialog, used with JFileChooser. 267 * @param approveButtonText The text for the approve button if JFileChooser is used. 268 * If FileDialog is used, then this argument is ignored. 269 * @return One of 270 * JFileChooser.CANCEL_OPTION, JFileChooser.APPROVE_OPTION 271 * JFileChooser.ERROR_OPTION is returned. If FileDialog is used, then either CANCEL_OPTION 272 * or APPROVE_OPTION is returned. 273 */ 274 public int showDialog(Container parent, String approveButtonText) { 275 if (_useFileDialog) { 276 _fileDialog.show(); 277 if (_fileDialog.getFile() == null) { 278 return JFileChooser.CANCEL_OPTION; 279 } else { 280 return JFileChooser.APPROVE_OPTION; 281 } 282 } else { 283 return _jFileChooser.showDialog(parent, approveButtonText); 284 } 285 } 286 287 /////////////////////////////////////////////////////////////////// 288 //// private fields //// 289 290 /** The java.awt.FileDialog that is used if _useFileDialog is true. */ 291 private FileDialog _fileDialog; 292 293 /** The javax.swing.JFileChooser that is used if _useFileDialog is false. */ 294 private JFileChooser _jFileChooser; 295 296 /** The mode of the dialog. One of 297 * JFileChooser.OPEN_DIALOG, JFileChooser.SAVE_DIALOG, JFileChooser.CUSTOM_DIALOG. 298 * CUSTOM_DIALOG is not supported with FileDialogs. 299 */ 300 private int _mode; 301 302 /** True if the directory warning was printed. */ 303 private static boolean _printedDirectoryWarning; 304 305 /** True if PtGUIUtilities.useFileDialog() returned true. */ 306 private boolean _useFileDialog; 307 308}