001 /* 002 * Copyright 2007, 2012 Stephen Fisher and Junhyong Kim, University of 003 * Pennsylvania. 004 * 005 * This file is part of Glo-DB. 006 * 007 * Glo-DB is free software: you can redistribute it and/or modify it 008 * under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * Glo-DB is distributed in the hope that it will be useful, but 013 * WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with Glo-DB. If not, see <http://www.gnu.org/licenses/>. 019 * 020 * @(#)GUIUtils.java 021 */ 022 023 package edu.upenn.gloDB.gui; 024 025 import edu.upenn.gloDB.*; 026 import edu.upenn.gloDB.io.*; 027 import java.io.File; 028 import java.util.ArrayList; 029 import java.util.HashSet; 030 import java.util.HashMap; 031 import java.util.Iterator; 032 import java.awt.*; 033 import java.awt.event.*; 034 import javax.swing.*; 035 import javax.swing.filechooser.*; 036 037 /** 038 * Static methods used throughout the GUI. 039 * 040 * @XXX The global file type descriptions and extensions be user 041 * modifiable. 042 * 043 * @author Stephen Fisher 044 * @version $Id: GUIUtils.java,v 1.17.2.21 2007/03/01 21:17:33 fisher Exp $ 045 */ 046 047 public class GUIUtils { 048 // private static JOptionPane dialog = new JOptionPane(); 049 private static JFileChooser fileChooser; 050 051 /** 052 * By using global static variables, these values will persist 053 * across instances of the open/save fileChoosers. 054 */ 055 private static boolean SHOW_ALL_FILES = GloDBMain.userDefaults.getBoolean("SHOW_ALL_FILES", 056 false); 057 private static boolean USE_FILE_EXTENSIONS = GloDBMain.userDefaults.getBoolean("USE_FILE_EXTENSIONS", 058 false); 059 060 //-------------------------------------------------------------------------- 061 // Getters and Setters 062 063 /** Set the SHOW_ALL_FILES flag. */ 064 public static void setShowAllFiles(boolean showAllFiles) { 065 SHOW_ALL_FILES = showAllFiles; 066 GloDBMain.userDefaults.putBoolean("SHOW_ALL_FILES", showAllFiles); 067 } 068 069 public static boolean showAllFiles() { return SHOW_ALL_FILES; } 070 071 /** Set the USE_FILE_EXTENSIONS flag. */ 072 public static void setUseFileExtensions(boolean useFileExtensions) { 073 USE_FILE_EXTENSIONS = useFileExtensions; 074 GloDBMain.userDefaults.putBoolean("USE_FILE_EXTENSIONS", useFileExtensions); 075 } 076 077 public static boolean useFileExtensions() { return USE_FILE_EXTENSIONS; } 078 079 //-------------------------------------------------------------------------- 080 // Miscellaneous Methods 081 082 /** RE-set GUI user defaults. */ 083 public static void resetGUIDefaults() { 084 setShowAllFiles(false); 085 setUseFileExtensions(false); 086 } 087 088 /** 089 * On Windows machines the path contains "\\", however, when 090 * converted to a String, this becomes "\". So we are doubling 091 * them here, to preserver the "\\". 092 */ 093 public static String getFilename(File file) { 094 return file.getAbsolutePath().replaceAll("\\\\","\\\\\\\\"); 095 } 096 097 /** Present a dialog box for renaming a particular Track. */ 098 public static String renameTrack(String id) { 099 // don't do anything if not a valid Track id 100 if (ObjectHandles.getTrack(id) == null) return ""; 101 102 String[] labels = {"Current Name", "New Name"}; 103 // use this to get the return value from FieldEditDialog 104 ArrayList textFields = new ArrayList(); 105 JTextField tf = new JTextField(20); 106 tf.setText(id); 107 tf.setEditable(false); 108 textFields.add(tf); 109 tf = new JTextField(20); 110 tf.setText(id); 111 tf.setEditable(true); 112 textFields.add(tf); 113 new FieldEditDialog("Rename Track", labels, textFields); 114 115 // check "exit code" for FieldEditDialog, if false then exit 116 Boolean exitCode = (Boolean) textFields.get(textFields.size()-1); 117 if (! exitCode.booleanValue()) return ""; 118 119 tf = (JTextField) textFields.get(1); 120 String newID = tf.getText(); 121 if ((newID.length() > 0) && (id.compareTo(newID) != 0)) { 122 ObjectHandles.renameTrack(id, newID); 123 Root.runCommand("renameTrack(\"" + id + "\", \"" + newID + "\")", false); 124 return newID; 125 } 126 127 return id; 128 } 129 130 /** 131 * Present a dialog box for changing sequence loader. 132 * @XXX This is currently hard coded for the FASTASequence loader. 133 */ 134 public static void newSequenceLoader(String id) { 135 // don't do anything if not a valid Sequence id 136 Sequence sequence = ObjectHandles.getSequence(id); 137 if (sequence == null) return; 138 139 String[] labels = {"Loader Type", "Source File"}; 140 // use this to get the return value from FieldEditDialog 141 ArrayList textFields = new ArrayList(); 142 JTextField tf = new JTextField(20); 143 // XXX don't allow user to change loader type 144 tf.setText("FASTA File Loader"); 145 /* 146 SequenceLoader loader = sequence.getDataLoader(); 147 if (loader == null) { 148 // default to FASTA File 149 tf.setText("FASTA File Loader"); 150 } else { 151 tf.setText(loader.toString()); 152 } 153 */ 154 tf.setEditable(false); 155 textFields.add(tf); 156 tf = new JTextField(20); 157 // XXX this assumes FASTASequence as loader 158 Object arg = sequence.getLoaderArg("filename"); 159 if (arg == null) arg = ""; 160 tf.setText(arg.toString()); 161 tf.setEditable(true); 162 textFields.add(tf); 163 new FieldEditDialog("Change Sequence Loader", labels, textFields); 164 165 // check "exit code" for FieldEditDialog, if false then exit 166 Boolean exitCode = (Boolean) textFields.get(textFields.size()-1); 167 if (! exitCode.booleanValue()) return; 168 169 tf = (JTextField) textFields.get(1); 170 String newSource = tf.getText(); 171 if (! GloDBUtils.isEmpty(newSource)) { 172 // XXX this only allows for loading of FASTA files 173 Root.runCommand("setSequenceSourceFile(\"" + id + "\", \"" + newSource + "\", FASTA)", true); 174 } 175 } 176 177 /** Present a dialog box for selecting a particular Track. */ 178 public static String trackSelector() { 179 // use this to get the return value from ObjectSelectorDialog 180 ArrayList out = new ArrayList(); 181 Object[] objects = ObjectHandles.trackPool.keySet().toArray(); 182 new ObjectSelectorDialog("Track Selector", objects, out); 183 184 if (out.size() > 0) { 185 return (String) out.get(0); 186 } else { 187 return ""; 188 } 189 } 190 191 /** Present a dialog box for selecting a particular Sequence. */ 192 public static String sequenceSelector() { 193 // use this to get the return value from ObjectSelectorDialog 194 ArrayList out = new ArrayList(); 195 Object[] objects = ObjectHandles.sequencePool.keySet().toArray(); 196 new ObjectSelectorDialog("Sequence Selector", objects, out); 197 198 if (out.size() > 0) { 199 return (String) out.get(0); 200 } else { 201 return ""; 202 } 203 } 204 205 /** Create a file chooser for opening files. */ 206 public static HashMap openFileChooser(int type, FileFilter filter) { 207 // use the current working directory 208 fileChooser = new JFileChooser("."); 209 210 // set the title 211 String title = "Load"; 212 if (type == GloDBUtils.TRACK) title += " Track"; 213 else if (type == GloDBUtils.SEQUENCE) title += " Sequence"; 214 title += " File"; 215 fileChooser.setDialogTitle(title); 216 217 // set the filter, if present 218 fileChooser.setAcceptAllFileFilterUsed(false); 219 HashSet dataTypes = FileIO.getDataTypes(type); 220 if (dataTypes != null) { 221 for (Iterator i = dataTypes.iterator(); i.hasNext();) { 222 DataFile dataFile = (DataFile) i.next(); 223 fileChooser.addChoosableFileFilter(dataFile.getFileFilter()); 224 } 225 226 // XXX not sure if we need to test to make sure 'filter' 227 // is a FileFilter in the FileIO set 228 if (filter != null) fileChooser.setFileFilter(filter); 229 } 230 231 // XXX these options need to be enabled and coded. 232 JPanel accessoryP = new JPanel(new GridLayout(2,0)); 233 JCheckBox allFilesCB = new JCheckBox("Show all files"); 234 allFilesCB.setSelected(showAllFiles()); 235 allFilesCB.setEnabled(true); 236 allFilesCB.setToolTipText("When checked, all files will be displayed, regardless of their file extensions."); 237 allFilesCB.addItemListener(new ItemListener() { 238 public void itemStateChanged(ItemEvent e) { 239 setShowAllFiles(((e.getStateChange() == ItemEvent.SELECTED) ? true : false)); 240 fileChooser.rescanCurrentDirectory(); 241 } 242 }); 243 accessoryP.add(allFilesCB); 244 JCheckBox useExtensionsCB = new JCheckBox("Use file extensions"); 245 useExtensionsCB.setSelected(useFileExtensions()); 246 useExtensionsCB.setEnabled(true); 247 useExtensionsCB.setToolTipText("When checked, this will force the use of file extensions. For example: \"data.gff\" instead of \"data\""); 248 useExtensionsCB.addItemListener(new ItemListener() { 249 public void itemStateChanged(ItemEvent e) { 250 setUseFileExtensions(((e.getStateChange() == ItemEvent.SELECTED) ? true : false)); 251 } 252 }); 253 accessoryP.add(useExtensionsCB); 254 fileChooser.setAccessory(accessoryP); 255 256 // open the file chooser 257 int status = fileChooser.showOpenDialog(null); 258 if (status == JFileChooser.APPROVE_OPTION) { 259 File file = fileChooser.getSelectedFile(); 260 String filename = getFilename(file); 261 262 filter = fileChooser.getFileFilter(); 263 String[] ext = {""}; 264 265 DataFile dataFile = FileIO.getDataType(type, filter.getDescription()); 266 if (dataFile != null) ext = dataFile.getExt(); 267 268 if (useFileExtensions()) { 269 // add filename extension, if necessary 270 if (ext.length > 0) { 271 boolean notFound = true; 272 int i = 0; 273 while (notFound && (i < ext.length)) { 274 if (filename.endsWith(ext[i])) notFound = false; 275 i++; 276 } 277 278 // the filename doesn't end with a valid 279 // extension, so loop through the extensions to 280 // see if we can find a file with one of the valid 281 // extensions. 282 if (notFound) { 283 for (i = 0; i < ext.length; i++) { 284 file = new File(filename + ext[i]); 285 if (file.exists()) { 286 filename += ext[i]; 287 break; 288 } 289 } 290 } 291 } 292 } 293 294 if (file.exists()) { 295 HashMap out = new HashMap(); 296 out.put("name", filename); 297 out.put("ext", ext); 298 out.put("filter", filter); 299 return out; 300 } 301 302 // the file doesn't exist, so rerun the file chooser 303 JOptionPane.showMessageDialog(new Frame(), 304 "The file \"" + filename 305 + "\" does not exist.", title, 306 JOptionPane.ERROR_MESSAGE); 307 return openFileChooser(type, filter); 308 } 309 310 return null; 311 } 312 313 /** 314 * Use a JFileChooser the get the file info for saving a Sequence. 315 */ 316 public static HashMap saveFileChooser(int type, FileFilter filter) { 317 // use the current working directory 318 fileChooser = new JFileChooser("."); 319 320 // set the title 321 String title = "Save"; 322 if (type == GloDBUtils.TRACK) title += " Track"; 323 else if (type == GloDBUtils.SEQUENCE) title += " Sequence"; 324 title += " File"; 325 fileChooser.setDialogTitle(title); 326 327 // set the filter, if present 328 fileChooser.setAcceptAllFileFilterUsed(false); 329 HashSet dataTypes = FileIO.getDataTypes(type); 330 if (dataTypes != null) { 331 for (Iterator i = dataTypes.iterator(); i.hasNext();) { 332 DataFile dataFile = (DataFile) i.next(); 333 fileChooser.addChoosableFileFilter(dataFile.getFileFilter()); 334 } 335 336 // XXX not sure if we need to test to make sure 'filter' 337 // is a FileFilter in FileIO 338 if (filter != null) fileChooser.setFileFilter(filter); 339 } 340 341 // XXX these options need to be enabled and coded. 342 JPanel accessoryP = new JPanel(new GridLayout(2,0)); 343 JCheckBox allFilesCB = new JCheckBox("Show all files"); 344 allFilesCB.setSelected(showAllFiles()); 345 allFilesCB.setEnabled(true); 346 allFilesCB.setToolTipText("When checked, all files will be displayed, regardless of their file extensions."); 347 allFilesCB.addItemListener(new ItemListener() { 348 public void itemStateChanged(ItemEvent e) { 349 setShowAllFiles(((e.getStateChange() == ItemEvent.SELECTED) ? true : false)); 350 fileChooser.rescanCurrentDirectory(); 351 } 352 }); 353 accessoryP.add(allFilesCB); 354 JCheckBox useExtensionsCB = new JCheckBox("Use file extensions"); 355 useExtensionsCB.setSelected(useFileExtensions()); 356 useExtensionsCB.setEnabled(true); 357 useExtensionsCB.setToolTipText("When checked, this will force the use of file extensions. For example: \"data.gff\" instead of \"data\""); 358 useExtensionsCB.addItemListener(new ItemListener() { 359 public void itemStateChanged(ItemEvent e) { 360 setUseFileExtensions(((e.getStateChange() == ItemEvent.SELECTED) ? true : false)); 361 fileChooser.rescanCurrentDirectory(); 362 } 363 }); 364 accessoryP.add(useExtensionsCB); 365 fileChooser.setAccessory(accessoryP); 366 367 // launch the file chooser 368 int status = fileChooser.showSaveDialog(null); 369 if (status == JFileChooser.APPROVE_OPTION) { 370 File file = fileChooser.getSelectedFile(); 371 String filename = getFilename(file); 372 373 filter = fileChooser.getFileFilter(); 374 String[] ext = {""}; 375 376 DataFile dataFile = FileIO.getDataType(type, filter.getDescription()); 377 if (dataFile != null) ext = dataFile.getExt(); 378 379 if (useFileExtensions()) { 380 // add filename extension, if necessary 381 if (ext.length > 0) { 382 boolean notFound = true; 383 int i = 0; 384 while (notFound && (i < ext.length)) { 385 if (filename.endsWith(ext[i])) notFound = false; 386 i++; 387 } 388 389 // the filename doesn't end with a valid ext, so 390 // loop through the extensions to see if we can 391 // find a file with one of the valid extensions. 392 // we could just take the first ext that isn't a 393 // valid file but it's assumed that users will be 394 // consistent in their use of extensions and thus 395 // if ".fasta" matches but ".fas" doesn't, we 396 // assume that ".fasta" is actually what the user 397 // wants to use. 398 if (notFound) { 399 i = 0; 400 // we're overloading 'notFound' by using it 401 // here as well as above. 402 while (notFound && (i < ext.length)) { 403 file = new File(filename + ext[i]); 404 if (file.exists()) notFound = false; 405 else i++; // don't increment if found 406 } 407 // if no file extensions match a file, then 408 // just use the first one in the list. 409 if (notFound) filename += ext[0]; 410 else filename += ext[i]; 411 } 412 } 413 } 414 415 if (! file.exists()) { 416 HashMap out = new HashMap(); 417 out.put("name", filename); 418 // out.put("desc", filter.getDescription()); 419 out.put("ext", ext); 420 out.put("filter", filter); 421 return out; 422 } 423 424 // the file exist, so check if want to overwrite the file 425 String msg = "The file \"" + file.getPath() + "\" already exists.\n"; 426 msg += "Do you want to overwrite the file?"; 427 Object[] options = {"Overwrite", "Cancel"}; 428 int flag = JOptionPane.showOptionDialog(null, msg, 429 "Overwrite Confirmation", 430 JOptionPane.YES_NO_OPTION, 431 JOptionPane.QUESTION_MESSAGE, 432 null, 433 options, 434 options[1]); 435 if (flag == JOptionPane.YES_OPTION) { // "Overwrite" 436 HashMap out = new HashMap(); 437 out.put("name", filename); 438 out.put("ext", ext); 439 out.put("filter", filter); 440 return out; 441 } else { 442 return saveFileChooser(type, filter); 443 } 444 } 445 446 return null; 447 } 448 449 } // GUIUtils.java