/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package gui.environment; import file.Codec; import file.EncodeException; import file.ParseException; import gui.editor.EditBlockPane; import gui.editor.EditorPane; import gui.grammar.GrammarInputPane; import java.awt.BorderLayout; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; /** * The EnvironmentFrame is the general sort of frame for holding * an environment. * * @author Thomas Finley */ public class EnvironmentFrame extends JFrame { /** * Instantiates a new EnvironmentFrame. This does not fill * the environment with anything. * * @param environment * the environment that the frame is created for */ public EnvironmentFrame(Environment environment) { this.environment = environment; environment.addFileChangeListener(new FileChangeListener() { public void fileChanged(FileChangeEvent e) { refreshTitle(); } }); initMenuBar(); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(environment, BorderLayout.CENTER); // Register this frame with the universe. myNumber = Universe.registerFrame(this); refreshTitle(); this.addWindowListener(new Listener()); this.setLocation(50, 50); this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); resizeWatcher(); } /** * Special constructor to create grammar environment from turing converted * @param environment * @param isTuring */ public EnvironmentFrame(Environment environment, int isTuring) { this.environment = environment; environment.addFileChangeListener(new FileChangeListener() { public void fileChanged(FileChangeEvent e) { refreshTitle(); } }); this.setJMenuBar(gui.menu.MenuBarCreator.getMenuBar(this, 0)); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(environment, BorderLayout.CENTER); // Register this frame with the universe. myNumber = Universe.registerFrame(this); refreshTitle(); this.addWindowListener(new Listener()); this.setLocation(50, 50); this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); resizeWatcher(); } /** * Returns a simple identifying string for this frame. * * @return a simple string that identifies this frame */ public String getDescription() { if (environment.getFile() == null) return ""; else if(environment.myObjects!=null && environment.getActive()!=null && (environment.getActive() instanceof EditorPane || environment.getActive() instanceof GrammarInputPane)){ return environment.getActive().getName(); } else return "(" + environment.getFile().getName() + ")"; } /** * Sets the title on this frame to be the name of the file for the * environment, or untitled if there is no file for this environment yet. */ protected void refreshTitle() { String title = DEFAULT_TITLE + " : " + getDescription(); setTitle(title); } /** * Initializes the menu bar for this frame. */ protected void initMenuBar() { this.setJMenuBar(gui.menu.MenuBarCreator.getMenuBar(this)); } /** * Returns the environment for this frame. * * @return the environment for this frame */ public Environment getEnvironment() { return environment; } /** * Saves the environment's object to a file. This serializes the object * found in the environment, and then writes it to the file of the * environment. * * @param saveAs * if true this will prompt the user with a save * file dialog box no matter what, otherwise the user will only * be prompted if the environment has no file * @return true if the save was a success, false * if it was not */ public boolean save(boolean saveAs) { File file = saveAs ? null : environment.getFile(); Codec codec = (Codec) environment.getEncoder(); Serializable object = environment.getObject(); if(environment.myObjects!=null && environment.getActive()!=null && environment.getActive() instanceof EditorPane){ EditorPane ep = (EditorPane)environment.getActive(); File expected = new File(ep.getAutomaton().getFilePath()+ep.getAutomaton().getFileName()); file = saveAs ? null : expected; object = ep.getAutomaton(); } else if(environment.myObjects!=null && environment.getActive()!=null && environment.getActive() instanceof GrammarInputPane){ GrammarInputPane ep = (GrammarInputPane)environment.getActive(); File expected = new File(ep.getGrammar().getFilePath()+ep.getGrammar().getFileName()); file = saveAs ? null : expected; object = ep.getGrammar(); } boolean blockEdit = false; if (environment.getActive() instanceof EditBlockPane) { EditBlockPane newPane = (EditBlockPane) environment.getActive(); object = newPane.getAutomaton(); blockEdit = true; } boolean badname = false; // Is this encoder valid? if (file != null && (codec == null || !codec.canEncode(object))) { JOptionPane .showMessageDialog( this, "We cannot write this structure in the same format\n" + "it was read as! Use Save As to select a new format.", "IO Error", JOptionPane.ERROR_MESSAGE); return false; } // Set the file filters. FileFilter[] filters = Universe.CHOOSER.getChoosableFileFilters(); for (int i = 0; i < filters.length; i++) Universe.CHOOSER.removeChoosableFileFilter(filters[i]); List encoders = Universe.CODEC_REGISTRY.getEncoders(object); Iterator it = encoders.iterator(); while (it.hasNext()) Universe.CHOOSER.addChoosableFileFilter((FileFilter) it.next()); if (codec != null && codec.canEncode(object)) { Universe.CHOOSER.setFileFilter(codec); } else { Universe.CHOOSER.setFileFilter((FileFilter) encoders.get(0)); } if(saveAs) Universe.CHOOSER.setDialogTitle("Save As"); // Check the name. if (file != null && codec != null) { // Get the suggested file name. String filename = file.getName(); String newname = codec.proposeFilename(filename, object); if (!filename.equals(newname)) { int result = JOptionPane.showConfirmDialog(this, "To save as a " + codec.getDescription() + ",\n" + "JFLAP wants to save " + filename + " to a new file\n" + "named " + newname + ". Is that OK?"); switch (result) { case JOptionPane.CANCEL_OPTION: // They cancelled. Get out of here. return false; case JOptionPane.NO_OPTION: // No, it's not OK! Use the original name. break; case JOptionPane.YES_OPTION: // Yes, we want the new name! Change the file. file = new File(file.getParent(), newname); badname = true; } } } // The save as loop. while (badname || file == null) { if (!badname) { int result = Universe.CHOOSER.showSaveDialog(this); if (result != JFileChooser.APPROVE_OPTION) return false; file = Universe.CHOOSER.getSelectedFile(); if(file != null){ // Get the suggested file name. String filename = file.getName(); codec = (Codec) Universe.CHOOSER.getFileFilter(); file = new File(Universe.CHOOSER.getCurrentDirectory(), codec.proposeFilename( filename, object)); // Check for the existing file. } else{ JOptionPane.showMessageDialog(null, "JFLAP could not determine the selected file name. Try again.", "Error", JOptionPane.ERROR_MESSAGE); file = null; continue; } } badname = false; if (file.exists()) { int result = JOptionPane.showConfirmDialog(this, "Overwrite " + file.getName() + "?"); switch (result) { case JOptionPane.CANCEL_OPTION: return false; case JOptionPane.NO_OPTION: file = null; continue; default: } } } // //System.out.println("CODEC: "+codec.getDescription()); Universe.CHOOSER.resetChoosableFileFilters(); // Use the codec to save the file. try { codec.encode(object, file, null); if (!blockEdit) environment.setFile(file); environment.setEncoder(codec); environment.clearDirty(); return true; } catch (ParseException e) { JOptionPane.showMessageDialog(this, e.getMessage(), "Write Error", JOptionPane.ERROR_MESSAGE); return false; } catch(EncodeException e){ JOptionPane.showMessageDialog(this, e.getMessage(), "Write Error", JOptionPane.ERROR_MESSAGE); return false; } } /** * Attempts to close an environment frame. * * @return true if the window was successfully closed, false * if the window could not be closed at this time (probably user * intervention) */ public boolean close() { if (environment.isDirty()) { File file = environment.getFile(); String title; if (file == null) title = "untitled"; else title = file.getName(); int result = JOptionPane.showConfirmDialog(this, "Save " + title + " before closing?"); if (result == JOptionPane.CANCEL_OPTION) return false; if (result == JOptionPane.YES_OPTION) save(false); //called by using alt-f4 in the window if (result==-1) return false; } dispose(); Universe.unregisterFrame(this); return true; } public void resizeWatcher(){ this.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(ComponentEvent event) { environment.resizeSplit(); } }); } /** * Returns the string that describes this frame. * * @return the string that describes this frame */ public String toString() { return getDescription(); } /** The environment that this frame displays. */ private Environment environment; /** The number of this environment frames. */ private int myNumber = 0xdeadbeef; /** The default title for these frames. */ private static final String DEFAULT_TITLE = "JFLAP"; /** * The window listener for this frame. */ private class Listener extends WindowAdapter { public void windowClosing(WindowEvent event) { close(); } } }