package edu.hws.eck.mdb; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.StringTokenizer; import java.util.prefs.*; /** * This class is used to run the mandelbrot viewer program as a standalone * application. The main routine creates a window of type MandelbrotFrame. * and shows it on the screen. This class also works with "preferences." * When the program exits, it saves the current window size and location to * the user's Java preferences. It also saves the currently selected * directory in the JFileChooser that is used when the user saves and opens * files. These values are restored from the user's preferences the next time * the program starts. */ public class Main { public static void main(String[] args) { final MandelbrotFrame frame = new MandelbrotFrame(); applyPreferences(frame); frame.adjustToScreenIfNecessary(); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.addWindowListener( new WindowAdapter() { // When the window is disposed, this event handler will // be notified. It will save current settings to the // user's preferences and terminate the program. public void windowClosed(WindowEvent evt) { frame.getMandelbrotPanel().getDisplay().shutDownThreads(); savePreferences(frame); System.exit(0); } }); frame.setVisible(true); } /** * Called when the program ends to try to save window bounds and current * directory to user's preferences, so they can be restored the next * time the program is run. Since this is not a critcal function, errors * are ignored. If an error occurs, the data simply won't be saved. */ private static void savePreferences(MandelbrotFrame frame) { try { String pathName = "/edu/hws/eck/mdb"; // The pathname uniquely identifies this program. (It is unique // because it comes from the package name, which should not be used // for any other program under Java's package naming guidelines. Preferences root = Preferences.userRoot(); Preferences node = root.node(pathName); // This "node" holds the preferences associated with the pathName. // Preferences take the form of key/value pairs, with put() and // get() operations for changing/reading values. Rectangle bounds = frame.getBounds(); String boundsString = bounds.x + "," + bounds.y + "," + bounds.width + "," + bounds.height; node.put("mandelbrot.window.bounds", boundsString); Menus menus = (Menus)frame.getJMenuBar(); String currentDir = menus.getSelectedDirectoryInFileChooser(); if (currentDir != null) node.put("mandelbort.filechooser.directory", currentDir); } catch (Exception e) { } } /** * This method is called when the program starts to read and apply the * preferences that were saved the last time the program ran. Since * this is not a critical funtion, errors are ignored. If an error * occurs, preferences will simply not be restored. */ private static void applyPreferences(MandelbrotFrame frame) { try { String pathName = "/edu/hws/eck/mdb"; // Identifies prefs for this program. Preferences root = Preferences.userRoot(); if (! root.nodeExists(pathName) ) return; // There are no saved prefs for this program yet. Preferences node = root.node(pathName); String boundsString = node.get("mandelbrot.window.bounds",null); if (boundsString != null) { // Try to restore window bounds, ignoring any error. String[] bounds = explode(boundsString,","); try { int x = Integer.parseInt(bounds[0]); int y = Integer.parseInt(bounds[1]); int w = Integer.parseInt(bounds[2]); int h = Integer.parseInt(bounds[3]); if (w > 5000 || h > 5000) throw new NumberFormatException(); // unreasonable values. frame.setBounds(x,y,w,h); frame.adjustToScreenIfNecessary(); } catch (NumberFormatException e) { } } Menus menus = (Menus)frame.getJMenuBar(); String directory = node.get("mandelbort.filechooser.directory", null); if (directory != null) { // Try to restore the current directory. menus.setSelectedDirectoryInFileChooser(directory); } } catch (Exception e) { } } /** * A convenience method that breaks up a string into tokens, where * the tokens are substrings seprated by specified delimiters. * For example, explode("ab,cde,f,ghij", ",") produces an array * of the four substrings "ab" "cde" "f" "ghi". */ private static String[] explode(String str, String separators) { StringTokenizer tokenizer = new StringTokenizer(str, separators); int ct = tokenizer.countTokens(); String[] tokens = new String[ct]; for (int i = 0; i < ct; i++) tokens[i] = tokenizer.nextToken(); return tokens; } }