📄 menus.java
字号:
package edu.hws.eck.mdb;import java.awt.*;import java.awt.event.*;import java.awt.image.BufferedImage;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import javax.imageio.ImageIO;import javax.swing.*;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.util.StringTokenizer;import org.w3c.dom.*;import java.io.*;/** * This class defines a JMenuBar for use with a MandelbrotPanel. This is a large * and complex class because it includes many nested classes and Actions that * do the work of carrying out menu commands. However, all the complexity is in * the private part of the class, and the class has only a very small public interface * consisting of just the contstructor and two methods that are used in implementing * "preferences" in Main.java. */public class Menus extends JMenuBar { /* * This file was modified on December 2, 2007 to fix a bug in the "LauncherApplet" * version of the program. A SecurityException was thrown on non-Mac-OS platforms * by the call to System.getProperty() in the makeAccelerator() method. This * prevented the LauncherApplet from opening a window (except under Mac OS). */ /** * Constructor creates the menu bar containing commands that apply to a * MandelbrotPanel. The configuration of the menu bar can be slightly * different, depending on the parameters to the constructor. The menu * bar always contains MaxIterations, Palette, and PaletteLength menus * that control the corresponding properties of the display. There is * always a Control menu; its contents can vary a little, but it always * contains: Restore All Defaults; Restore Default Limits; Restore Previous Limits; * and "Set Limits". A File menu might or might not be included. * @param owner The MandelbrotPanel that will be managed by this menu bar. This * variable is also used fof access to the MandelbrotDisplay that is * contained in the panel. This parameter cannot be null. * @param frame the frame, if any, that contains the MandelbrotPanel. For a * MandelbrotPanel in an applet on a web page, this will be null. If frame * is non-null, then accelerators are added to some of the menu commands. * Also, a "Set Image Size" command is added to the Control menu; this command * requires the frame to change size and so cannot be carried out if there * is no frame. * @param runningAsApplet true if the program is running as a standalone application, * false if not. (Note that the frame can be non-null even for an applet, if * LauncherApplet is used.) For an applet, there is no File menu. For a standalong * application, there is a file menu that contains a Save Params, Open Params, * Save Image, and Quit command. If the program is running as an applet, but * with a frame, then a Close command is added to the control menu. */ public Menus(MandelbrotPanel owner, MandelbrotFrame frame, boolean runningAsApplet) { this.owner = owner; this.frame = frame; paletteManager = new PaletteManager(); // Manages Palette menu. paletteLengthManager = new PaletteLengthManager(); // Manages PaletteLength menu. maxIterationsManager = new MaxIterationsManager(); // Manages MaxIterations menu. // (Note that the Actions that carry out commands in other menus are // defined as instance variables that are initialized as part of their // declarations later in this class.) if (frame != null) { // Add accelerator keys. saveParams.putValue(Action.ACCELERATOR_KEY, makeAccelerator("S")); saveImage.putValue(Action.ACCELERATOR_KEY, makeAccelerator("shift S")); openParams.putValue(Action.ACCELERATOR_KEY, makeAccelerator("O")); if (runningAsApplet) { // "Close" and "Quit" are actually implemented in the same way; // both of them just dispose of the frame. The name "Quit" is // used in standalone applications; "Close" is used in applets. close.putValue(Action.ACCELERATOR_KEY, makeAccelerator("W")); } else { close.putValue(Action.NAME, "Quit"); close.putValue(Action.ACCELERATOR_KEY, makeAccelerator("Q")); } defaultLimits.putValue(Action.ACCELERATOR_KEY, makeAccelerator("R")); allDefaults.putValue(Action.ACCELERATOR_KEY, makeAccelerator("shift R")); undoChangeOfLimits.putValue(Action.ACCELERATOR_KEY, makeAccelerator("U")); showLimits.putValue(Action.ACCELERATOR_KEY, makeAccelerator("L")); setLimits.putValue(Action.ACCELERATOR_KEY, makeAccelerator("shift L")); setImageSize.putValue(Action.ACCELERATOR_KEY, makeAccelerator("shift I")); paletteManager.items[0].setAccelerator(makeAccelerator("T")); paletteLengthManager.items[0].setAccelerator(makeAccelerator("M")); } if (!runningAsApplet) { // Add a File menu, and add items to the menu. JMenu fileMenu = new JMenu(I18n.tr("menu.file")); add(fileMenu); fileMenu.add(saveParams); fileMenu.add(openParams); fileMenu.addSeparator(); fileMenu.add(saveImage); fileMenu.addSeparator(); fileMenu.add(close); } // Create the other menus and add them to this menu bar. JMenu controlMenu = new JMenu(I18n.tr("menu.control")); add(controlMenu); JMenu maxIterationsMenu = new JMenu(I18n.tr("menu.maxIterations")); add(maxIterationsMenu); JMenu paletteMenu = new JMenu(I18n.tr("menu.palette")); add(paletteMenu); JMenu paletteLengthMenu = new JMenu(I18n.tr("menu.paletteLength")); add(paletteLengthMenu); // Add items to the Control menu. controlMenu.add(allDefaults); controlMenu.addSeparator(); controlMenu.add(defaultLimits); controlMenu.add(undoChangeOfLimits); undoChangeOfLimits.setEnabled(false); controlMenu.add(showLimits); controlMenu.add(setLimits); if (frame != null) { controlMenu.addSeparator(); controlMenu.add(setImageSize); } if (frame != null && runningAsApplet) { controlMenu.addSeparator(); controlMenu.add(close); } // Add items to the other three menus. These are created by the "manager" objects. for (JMenuItem item : paletteManager.items) paletteMenu.add(item); for (JMenuItem item : paletteLengthManager.items) paletteLengthMenu.add(item); for (JMenuItem item : maxIterationsManager.items) maxIterationsMenu.add(item); // Add property change listeners to the MandebrotDisplay, so that this // menu bar can be notified when certain changes occur in the display. owner.getDisplay().addPropertyChangeListener(MandelbrotDisplay.LIMITS_PROPERTY, new PropertyChangeListener() { // This listener responds when the limits are changed in the // display. The only action is to save the old values of // the limits, so thay they can be used in the Restore Previous Limits // command. (Also, the command is enabled because a previous set // set of limits is now available.) public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName() == MandelbrotDisplay.LIMITS_PROPERTY) { previousLimits = (double[])e.getOldValue(); undoChangeOfLimits.setEnabled(true); } } }); owner.getDisplay().addPropertyChangeListener(MandelbrotDisplay.STATUS_PROPERTY, new PropertyChangeListener() { // This listener responds when the "status" of the display // changes. The status is used, in the newDisplayStatus method, // to enable and disable menu commands that should only be // be available when the display is in a certain state. public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName() == MandelbrotDisplay.STATUS_PROPERTY) { newDisplayStatus(e.getNewValue()); } } }); newDisplayStatus(owner.getDisplay().getStatus()); // Enable/disable commands based on initial display status. } // end constructor /** * If the fileDialog has been used to carry out one of the save/open commands, * then some directory will be selected in the dialog box. This method returns * an absolute path name for that selected directory. This method is used * by Main.java to find out the selected directory when the program ends. * The directory is saved in user preferences and is restored the next time * the program is run. */ public String getSelectedDirectoryInFileChooser() { if (fileDialog == null) return null; else { File dir = fileDialog.getCurrentDirectory(); if (dir == null) return null; else return dir.getAbsolutePath(); } } /** * This sets the selected directory in the file dialog. This method * is called by Main.java when the program starts to restore the directory * that was saved the last time the program was run (by the same user). * @param path absolute path name to the directory; if this is * not the path name of an actual directory, then the dialog's * selected directory is not set. */ public void setSelectedDirectoryInFileChooser(String path) { File dir = new File(path); if (dir.isDirectory()) { if (fileDialog == null) fileDialog = new JFileChooser(); fileDialog.setCurrentDirectory(dir); } } /** * Produces an XML representation of the current settings. * This is used by the Open Params action to restore the setting of the program based * on the contents of an XML file. It is also used by the MandelbrotApplet class * to implement an Examples menu. Currently, the image size is NOT adjusted to * the value in the file; the same picture that was saved is shown, but possibly at * a different size. (Note: This method is defective because I was lazy. If an * error occurs in the middle of processing the data, some of the setting will be * applied but not others. This ignores the guideline that the file should be * completely read and checked before any changes are made to the state of the * program.) */ public void retrieveSettingsFromXML(Document xmlDoc) { Element docElement = xmlDoc.getDocumentElement(); String docName = docElement.getTagName(); if (! docName.equalsIgnoreCase("mandelbrot_settings")) throw new IllegalArgumentException(I18n.tr("xml.error.wrongType",docName)); String version = docElement.getAttribute("version"); if ( ! version.equalsIgnoreCase("edu.hws.eck.mdb/1.0")) throw new IllegalArgumentException(I18n.tr("xml.error.wrongSettingsVersion")); NodeList nodes = docElement.getChildNodes(); int ct = nodes.getLength(); for (int i = 0; i < ct; i++) { Node node = nodes.item(i); if (node instanceof Element) { String name = ((Element)node).getTagName(); String value = ((Element)node).getAttribute("value"); try { if (name.equalsIgnoreCase("palettetype")) paletteManager.setValueFromString(value); else if (name.equalsIgnoreCase("palettelength")) paletteLengthManager.setValueFromString(value); else if (name.equalsIgnoreCase("maxiterations")) maxIterationsManager.setValueFromString(value); else if (name.equalsIgnoreCase("limits")) { String[] limitStrings = explode(value,","); double xmin = Double.parseDouble(limitStrings[0]); double xmax = Double.parseDouble(limitStrings[1]); double ymin = Double.parseDouble(limitStrings[2]); double ymax = Double.parseDouble(limitStrings[3]); owner.getDisplay().setLimits(xmin,xmax,ymin,ymax); } } catch (Exception e) { throw new IllegalArgumentException(I18n.tr("xml.error.illegalSettingsValue",name,value)); } } } } /** * This is used by the Save Params action to create an XML representation of * the current settings. (It is not currently used outside this class in the Mandelbrot * Viewer program.) */ public String currentSettingsAsXML() { StringBuffer buffer = new StringBuffer(); buffer.append("<?xml version='1.0'?>\n"); buffer.append("<mandelbrot_settings version='edu.hws.eck.mdb/1.0'>\n"); double[] limits = owner.getDisplay().getLimits(); String limitString = limits[0] + "," + limits[1] + "," + limits[2] + "," + limits[3]; buffer.append("<limits value='"+ limitString + "'/>\n"); String sizeString = owner.getDisplay().getWidth() + "," + owner.getDisplay().getHeight(); buffer.append("<imagesize value='"+ sizeString + "'/>\n"); buffer.append("<maxiterations value='" + maxIterationsManager.valueAsString() + "'/>\n"); buffer.append("<palettetype value='" + paletteManager.valueAsString() + "'/>\n"); buffer.append("<palettelength value='" + paletteLengthManager.valueAsString() + "'/>\n"); buffer.append("</mandelbrot_settings>\n"); return buffer.toString(); } //------------------ Everything after this point is private -------------------------- private MandelbrotPanel owner; // From the parameter to the constructor. private MandelbrotFrame frame; // From the parameter to the constructor, private PaletteManager paletteManager; // Manages Palette menu; defined by nested class below. private PaletteLengthManager paletteLengthManager; // Manages PaletteLength menu; defined by nested class below. private MaxIterationsManager maxIterationsManager; // Manages MaxIterations menu; defined by nested class below. private JFileChooser fileDialog; // File dialog for open and save commands. private double[] previousLimits; // For the Restore Previous Limits command. private String commandKey; // "ctrl " or "meta ", depending on platform; used only in makeAccelerator() /** * Makes an accelerator keystroke from description, with "ctrl " or "meta " * tacked onto the front. Used only in the constructor. */ private KeyStroke makeAccelerator(String description) { if (commandKey == null) { commandKey = "cntr "; try { // try..catch added December 2007 to fix bug noted at top of this file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -