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