package edu.hws.eck.mdbfx; import javafx.application.Application; import javafx.geometry.Rectangle2D; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.stage.Screen; import java.util.prefs.*; /** * This class is used to run the Mandelbrot viewer program. * The start method shows a window containing a MandelbrotPane. * This class also works with "preferences." When the window is closed, * an event handler saves the current window size and location to * the user's Java preferences. It also saves the most recently selected * directory where the user saved or opened a file. These values are restored * from the user's preferences the next time the program starts. */ public class Main extends Application { /* The Mandelbrot program defined in package edu.hws.edu.mdbfx is a JavFX * port of an older Swing version of the program. Some things could have * been done in a more JavaFX-like way, and since it is a fairly complex * program, it is likely that the port has introduced a few unnoticed bugs. * For a nicer Mandelbrot program in Java, see * http://math.hws.edu/eck/js/mandelbrot/java/MB-java.html * A pretty nice JavaScript version is at * http://math.hws.edu/eck/js/mandelbrot/MB.html */ public static void main(String[] args) { launch(args); } /** * Open a window containing a MandelbrotPane, and apply preferences * from previous runs if possible. */ public void start(Stage stage) { MandelbrotPane content = new MandelbrotPane(); stage.setScene( new Scene(content) ); stage.setOnHidden( e -> { content.closing(); savePreferences(stage,content); } ); applyPreferences(stage, content); stage.setMinHeight(240); stage.setMinWidth(240); stage.setTitle(I18n.tr("frame.title")); stage.show(); } /** * 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 critical function, errors * are ignored. If an error occurs, the data simply won't be saved. */ private static void savePreferences(Stage window, MandelbrotPane content) { try { String pathName = "/edu/hws/eck/mdbfx"; // 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. String boundsString = (int)window.getX() + "," + (int)window.getY() + "," + (int)window.getWidth() + "," + (int)window.getHeight(); node.put("mandelbrot.window.bounds", boundsString); Menus menus = content.getMenus(); String currentDir = menus.getSelectedDirectoryInFileChooser(); if (currentDir != null) node.put("mandelbrot.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 function, errors are ignored. If an error * occurs, preferences will simply not be restored. */ private static void applyPreferences(Stage window, MandelbrotPane content) { try { String pathName = "/edu/hws/eck/mdbfx"; // 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 = boundsString.split(","); try { // set window bounds, after running some sanity checks double x = Integer.parseInt(bounds[0]); double y = Integer.parseInt(bounds[1]); double w = Integer.parseInt(bounds[2]); double h = Integer.parseInt(bounds[3]); if (w <= 0 || h <= 0 || w > 5000 || h > 5000) throw new NumberFormatException(); // unreasonable values. Rectangle2D screen = Screen.getPrimary().getVisualBounds(); if (x < screen.getMinX() || x > screen.getMaxX() - 300) x = screen.getMinX() + 20; if (y < screen.getMinY() || y > screen.getMaxY() - 200) y = screen.getMinY() + 20; if (w < 300) w = 300; else if (x + w > screen.getMaxX()) w = screen.getMaxX() - x; if (h < 200) h = 200; else if (y + h > screen.getMaxY()) h = screen.getMaxY() - y; window.setX(x); window.setY(y); window.setWidth(w); window.setHeight(h); } catch (NumberFormatException e) { // in case of error, ignore the bounds } } Menus menus = content.getMenus(); String directory = node.get("mandelbrot.filechooser.directory", null); if (directory != null) { // Try to restore the current directory. menus.setSelectedDirectoryInFileChooser(directory); } } catch (Exception e) { } } }