001    /*
002     * CRIMSON
003     * Copyright (c) 2006, Stephen Fisher, Susan Davidson, and Junhyong Kim, 
004     * University of Pennsylvania.
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License as
008     * published by the Free Software Foundation; either version 2 of the
009     * License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful, but
012     * WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     * 02110-1301 USA.
020     *
021     * @(#)GUIUtils.java
022     */
023    
024    package edu.upenn.crimson.gui;
025    
026    import edu.upenn.crimson.*;
027    import edu.upenn.crimson.io.*;
028    import java.io.File;
029    import java.util.ArrayList;
030    import java.awt.*;
031    import java.awt.Toolkit;
032    import javax.swing.*;
033    import javax.swing.filechooser.*;
034    import javax.swing.text.*;
035    import walrus.*;
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.40 2007/05/16 18:55:58 fisher Exp $
045     */
046    
047    public class GUIUtils {
048             /** 
049              * The file chooser begins with the current working directory.
050              * This is not saved across sessions.
051              */
052             private static JFileChooser fileChooser = new JFileChooser(".");
053    
054             /** 
055              * By using global static variables, these values will persist
056              * across instances of the open/save fileChoosers.
057              */
058             private static boolean SHOW_ALL_FILES = CrimsonMain.userDefaults.getBoolean("SHOW_ALL_FILES", 
059                                                                                                                                                                                                                      false);
060             private static boolean USE_FILE_EXTENSIONS = CrimsonMain.userDefaults.getBoolean("USE_FILE_EXTENSIONS", 
061                                                                                                                                                                                                                                     false);
062    
063        //--------------------------------------------------------------------------
064        // Getters and Setters
065             
066             /** Set the SHOW_ALL_FILES flag. */
067        public static void setShowAllFiles(boolean showAllFiles) { 
068                      SHOW_ALL_FILES = showAllFiles; 
069                      CrimsonMain.userDefaults.putBoolean("SHOW_ALL_FILES", showAllFiles);
070             }
071    
072             public static boolean showAllFiles() { return SHOW_ALL_FILES; }
073    
074             /** Set the USE_FILE_EXTENSIONS flag. */
075        public static void setUseFileExtensions(boolean useFileExtensions) { 
076                      USE_FILE_EXTENSIONS = useFileExtensions; 
077                      CrimsonMain.userDefaults.putBoolean("USE_FILE_EXTENSIONS", useFileExtensions);
078             }
079    
080             public static boolean useFileExtensions() { return USE_FILE_EXTENSIONS; }
081    
082             public static FileFilter getPyFilter() { return new PyFilter(); }
083    
084             public static DocumentFilter getDocLengthFilter() { return new DocumentLengthFilter(); }
085    
086        //--------------------------------------------------------------------------
087        // Miscellaneous Methods
088    
089             /** This will start a Walrus 3D session using the file given. */
090             public static void launchWalrus(String filename) {
091                      H3Main w = new H3Main();
092                      w.userLoadFile(filename);
093                      w.handleStartRenderingRequest();
094             }
095    
096             /** RE-set GUI user defaults.  */
097        public static void resetGUIDefaults() { 
098                      setShowAllFiles(false);
099                      setUseFileExtensions(false);
100             }
101    
102             /**
103              * On Windows machines the path contains "\\", however, when
104              * converted to a String, this becomes "\".  So we are doubling
105              * them here, to preserver the "\\".
106              */
107             public static String getFilename(File file) {
108                      if (file == null) return "";
109                      else return file.getAbsolutePath().replaceAll("\\\\","\\\\\\\\");
110             }
111    
112             public static void setDBType() {
113                      if (Database.isOpen()) {
114                                    String msg = "A database is already open. Continuing will close the current database.";
115                                    Object[] options = {"Continue", "Cancel"};
116                                    int flag = JOptionPane.showOptionDialog(null, msg,
117                                                                                                                                             "Open Database Confirmation",
118                                                                                                                                             JOptionPane.YES_NO_OPTION,
119                                                                                                                                             JOptionPane.QUESTION_MESSAGE,
120                                                                                                                                             null,
121                                                                                                                                             options,
122                                                                                                                                             options[1]);
123                                    if (flag == JOptionPane.NO_OPTION) { // "Cancel"
124                                             return;
125                                    }
126                      }
127    
128                      ArrayList out = new ArrayList();
129                      new ObjectSelectorDialog("Database Selector", SQL.getDBTypes(), out);
130    
131                      if (out.size() > 0) {
132                                    // if a database is open, then close it now
133                                    if (Database.isOpen()) Database.close();
134    
135                                    Root.runCommand("setDBType(\"" + (String) out.get(0) + "\")");
136                      }
137             }
138    
139    
140             /**
141              * Use a FieldEditDialog to query the user for 'username',
142              * 'password', and 'database' info and then use this info to open
143              * a connection to the database.  The 'username' and 'database'
144              * will be saved as an application preference so they can be used
145              * as defaults the next time around.
146              */
147             public static void openDatabase() {
148                      String[] labels = {" Username", " Password:", " " + SQL.getDBType().toUpperCase() + " Server", " Port", " Database (SID)"};
149    
150                      // use this to get the return value from FieldEditDialog
151                      ArrayList textFields = new ArrayList();
152    
153                      // get the values the user entered the last time, for
154                      // 'username' and 'database,' and use them as the default
155                      // values here
156                      JTextField username = new JTextField(20);
157                      username.setText(CrimsonUtils.getUsername());
158                      JTextField server = new JTextField(30);
159                      server.setText(CrimsonUtils.getServer());
160                      JTextField port = new JTextField(5);
161                      port.setText(Integer.toString(CrimsonUtils.getPort()));
162                      JTextField database = new JTextField(30);
163                      database.setText(CrimsonUtils.getDatabase());
164    
165                      textFields.add(username);
166                      textFields.add(new JPasswordField(20));
167                      textFields.add(server);
168                      textFields.add(port);
169                      textFields.add(database);
170    
171                      new FieldEditDialog("Open Database", labels, textFields);
172    
173                      // check "exit code" for FieldEditDialog, if false then exit
174                      Boolean exitCode = (Boolean) textFields.get(textFields.size()-1);
175                      if (! exitCode.booleanValue()) return;
176    
177                      // Don't actually include password here or it would print on
178                      // the screen.  Because we don't want to the password to show,
179                      // we have to run the command directly, not through console.
180                      String msg = "openDatabase(\"" + username.getText();
181                      msg += "\", \"******\", \"" + server.getText() + "\", ";
182                      msg += port.getText() + ", \"" + database.getText() + "\")";
183                      Root.runCommand(msg, false);
184    
185                      // open the database connection.  If successful, the username,
186                      // database, server, and port values will be saved as defaults
187                      String password = ((JTextField) textFields.get(1)).getText();
188                      Database.open(username.getText(), password, server.getText(), 
189                                                             Integer.parseInt(port.getText()), database.getText());
190             }
191    
192             /** Create a file chooser for selecting a directory. */
193             public static File directoryChooser() {
194                      // use the current working directory
195                      //              fileChooser = new JFileChooser(".");
196    
197                      // set the title
198                      fileChooser.setDialogTitle("Select Directory");
199    
200                      // set the default filename
201                      fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
202    
203                      // save the file chooser
204                      int status = fileChooser.showOpenDialog(null);
205                      if (status == JFileChooser.APPROVE_OPTION) {
206                                    File file = fileChooser.getSelectedFile();
207    
208                                    if (file.exists()) return file;
209    
210                                    // the file exist, so rerun the file chooser
211                                    String msg = "The directory \"" + getFilename(file) + "\" doesn't exist.\n";
212                                    msg += "Do you want to create the directory?";
213                                    int flag = JOptionPane.showConfirmDialog(null, msg,
214                                                                                                                                             "Overwrite Confirmation",
215                                                                                                                                             JOptionPane.YES_NO_OPTION);
216                                    if (flag == JOptionPane.YES_OPTION) { // "Create"
217                                             file.mkdir();
218                                             return file;
219                                    } else {
220                                             return directoryChooser();
221                                    }
222                      }
223    
224                      return null;
225        }
226    
227             /** Create a file chooser for opening files. */
228             public static File openFileChooser(String title, FileFilter filter) {
229                      // use the current working directory
230                      //              fileChooser = new JFileChooser(".");
231    
232                      // set the title
233                      fileChooser.setDialogTitle(title);
234    
235                      // set the file filter
236                      if (filter != null) fileChooser.setFileFilter(filter);
237    
238                      // open the file chooser
239                      int status = fileChooser.showOpenDialog(null);
240                      if (status == JFileChooser.APPROVE_OPTION) {
241                File file = fileChooser.getSelectedFile();
242    
243                                    if (file.exists()) return file;
244    
245                                    // the file doesn't exist, so rerun the file chooser
246                                    JOptionPane.showMessageDialog(new Frame(), 
247                                                                                                                    "The file \"" + getFilename(file)
248                                                                                                                    + "\" does not exist.", title,
249                                                                                                                    JOptionPane.ERROR_MESSAGE);
250                                    return openFileChooser(title, filter);
251                      }
252    
253                      return null;
254        }
255    
256             /** Create a file chooser for saving files. */
257             public static File saveFileChooser(String title, String name, FileFilter filter) {
258                      // use the current working directory
259                      //              fileChooser = new JFileChooser(".");
260    
261                      // set the title
262                      fileChooser.setDialogTitle(title);
263    
264                      // set the default filename
265                      fileChooser.setSelectedFile(new File(name));
266    
267                      // set the file filter
268                      if (filter != null) fileChooser.setFileFilter(filter);
269    
270                      // save the file chooser
271                      int status = fileChooser.showSaveDialog(null);
272                      if (status == JFileChooser.APPROVE_OPTION) {
273                                    File file = fileChooser.getSelectedFile();
274    
275                                    if (! file.exists()) return file;
276    
277                                    // the file exist, so rerun the file chooser
278                                    String msg = "The file \"" + getFilename(file) + "\" already exists.\n";
279                                    msg += "Do you want to overwrite the file?";
280                                    Object[] options = {"Overwrite", "Cancel"};
281                                    int flag = JOptionPane.showOptionDialog(null, msg,
282                                                                                                                                             "Overwrite Confirmation",
283                                                                                                                                             JOptionPane.YES_NO_OPTION,
284                                                                                                                                             JOptionPane.QUESTION_MESSAGE,
285                                                                                                                                             null,
286                                                                                                                                             options,
287                                                                                                                                             options[1]);
288                                    if (flag == JOptionPane.YES_OPTION) { // "Overwrite"
289                                             return file;
290                                    } else {
291                                             return saveFileChooser(title, name, filter);
292                                    }
293                      }
294    
295                      return null;
296        }
297    
298             /** Python specific FileFilter. */
299             public static class PyFilter extends FileFilter {
300                      public boolean accept(File f) {
301                                    // accept directories
302                                    if (f.isDirectory()) return true;
303                                    
304                                    // accept files ending in '.py'
305                                    if ((f.getName()).endsWith(".py")) return true;
306    
307                                    return false;
308                      }
309    
310                      public String getDescription() { return "Python scripts"; }
311             }
312    
313             /** Filter used to limit JTextAreas to 4000 characters. */
314             public static class DocumentLengthFilter extends DocumentFilter {
315                      final int MAX_LENGTH = 4000;
316                      
317                      public void insertString(FilterBypass doc, int offset, String str, 
318                                                                                            AttributeSet attrib)    throws BadLocationException {
319                                    if ((doc.getDocument().getLength() + str.length()) <= MAX_LENGTH)
320                                             // the text fits, so add it
321                                             super.insertString(doc, offset, str, attrib);
322                                    else {
323                                             // the string is to large so only add up to the limit
324                                             int avail = MAX_LENGTH - doc.getDocument().getLength();
325                                             if (avail > 0) super.insertString(doc, offset, str.substring(0,avail), attrib);
326                                             Toolkit.getDefaultToolkit().beep();
327                                    }
328                      }
329                      
330                      public void replace(FilterBypass doc, int offset, int len, String str, 
331                                                                             AttributeSet attrib) throws BadLocationException {
332                                    if ((doc.getDocument().getLength() + str.length() - len) <= MAX_LENGTH)
333                                             // the text fits, so add it
334                                             super.replace(doc, offset, len, str, attrib);
335                                    else {
336                                             // the string is to large so only add up to the limit
337                                             int avail = MAX_LENGTH - (doc.getDocument().getLength() - len);
338                                             if (avail > 0) super.replace(doc, offset, len, str.substring(0,avail), attrib);
339                                             Toolkit.getDefaultToolkit().beep();
340                                    }
341                      }
342                      
343             }
344    } // GUIUtils.java