/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.HeadlessException; import java.awt.Toolkit; import java.awt.Window; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Iterator; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.opensourcephysics.controls.OSPLog; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.controls.XMLControlElement; import org.opensourcephysics.controls.XMLProperty; import org.opensourcephysics.controls.XMLTreeChooser; import org.opensourcephysics.controls.XMLTreePanel; import org.opensourcephysics.display.axes.DrawableAxes; import org.opensourcephysics.tools.FontSizer; import org.opensourcephysics.tools.Job; import org.opensourcephysics.tools.LocalJob; import org.opensourcephysics.tools.SnapshotTool; import org.opensourcephysics.tools.Tool; import org.opensourcephysics.tools.VideoTool; /** * Drawing Frame: a frame that contains a drawing panel. * * @author Wolfgang Christian * @created July 16, 2004 * @version 1.1 */ public class DrawingFrame extends OSPFrame implements ClipboardOwner { // protected static String resourcesPath = "/org/opensourcephysics/resources/display/"; // protected static String defaultToolsFileName = "drawing_tools.xml"; protected JMenu fileMenu, editMenu; protected JMenuItem copyItem, pasteItem, replaceItem; protected DrawingPanel drawingPanel; protected final static int MENU_SHORTCUT_KEY_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); protected Window customInspector; // optional custom inspector for this frame protected Tool reply; /** * DrawingFrame constructor that creates a default DrawingPanel. * * The default DrawingPanel is an InteractivePanel. */ public DrawingFrame() { this(DisplayRes.getString("DrawingFrame.DefaultTitle"), new InteractivePanel()); //$NON-NLS-1$ } /** * DrawingFrame constructor specifying the DrawingPanel that will be placed * in the center of the content pane. * * @param drawingPanel */ public DrawingFrame(DrawingPanel drawingPanel) { this(DisplayRes.getString("DrawingFrame.DefaultTitle"), drawingPanel); //$NON-NLS-1$ } /** * DrawingFrame constructor specifying the title and the DrawingPanel that * will be placed in the center of the content pane. * * @param title * @param _drawingPanel */ public DrawingFrame(String title, DrawingPanel _drawingPanel) { super(title); // forces dependence on the DatasetTool class; // add or remove the next line if you do not want the DatasetTool in your jar // org.opensourcephysics.tools.DataTool.loadClass = true; drawingPanel = _drawingPanel; if(drawingPanel!=null) { getContentPane().add(drawingPanel, BorderLayout.CENTER); } getContentPane().add(buttonPanel, BorderLayout.SOUTH); // buttons are added using addButton method. pack(); if(!OSPRuntime.appletMode) { createMenuBar(); } // responds to data from the Data Tool reply = new Tool() { public void send(Job job, Tool replyTo) throws RemoteException { XMLControlElement control = new XMLControlElement(); try { control.readXML(job.getXML()); } catch(RemoteException ex) {} ArrayList<?> datasets = drawingPanel.getObjectOfClass(Dataset.class); Iterator<?> it = control.getObjects(Dataset.class).iterator(); while(it.hasNext()) { Dataset newData = (Dataset) it.next(); int id = newData.getID(); for(int i = 0, n = datasets.size(); i<n; i++) { if(((Dataset) datasets.get(i)).getID()==id) { XMLControl xml = new XMLControlElement(newData); // convert the source to xml Dataset.getLoader().loadObject(xml, datasets.get(i)); // copy the data to the destination break; } } } drawingPanel.repaint(); } }; } /** * Renders the drawing panel if the frame is showing and not iconified. */ public void render() { if(isIconified()||!isShowing()) { return; } if(drawingPanel!=null) { drawingPanel.render(); } else { repaint(); } } /** * Invalidates image buffers if a drawing panel buffered. */ public void invalidateImage() { if(drawingPanel!=null) { drawingPanel.invalidateImage(); } } /** * Gets the drawing panel. * * @return the drawingPanel */ public DrawingPanel getDrawingPanel() { return drawingPanel; } /** * Sets the label for the X (horizontal) axis. * * @param label the label */ public void setXLabel(String label) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setXLabel(label); } } /** * Sets the label for the Y (vertical) axis. * * @param label the label */ public void setYLabel(String label) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setYLabel(label); } } /** * Converts to polar coordinates. * * @param plotTitle String * @param deltaR double */ public void setPolar(String plotTitle, double deltaR) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setPolar(plotTitle, deltaR); } } /** * Converts to cartesian coordinates. * * * @param xLabel String * @param yLabel String * @param plotTitle String */ public void setCartesian(String xLabel, String yLabel, String plotTitle) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setCartesian(xLabel, yLabel, plotTitle); } } /** * Limits the xmin and xmax values during autoscaling so that the mininimum value * will be no greater than the floor and the maximum value will be no * smaller than the ceil. * * Setting a floor or ceil value to <code>Double.NaN<\code> will disable that limit. * * @param floor the xfloor value * @param ceil the xceil value */ public void limitAutoscaleX(double floor, double ceil) { drawingPanel.limitAutoscaleX(floor, ceil); } /** * Limits ymin and ymax values during autoscaling so that the mininimum value * will be no greater than the floor and the maximum value will be no * smaller than the ceil. * * Setting a floor or ceil value to <code>Double.NaN<\code> will disable that limit. * * @param floor the yfloor value * @param ceil the yceil value */ public void limitAutoscaleY(double floor, double ceil) { drawingPanel.limitAutoscaleY(floor, ceil); } /** * Autoscale the drawing panel's x axis using min and max values. * from measurable objects. * @param autoscale */ public void setAutoscaleX(boolean autoscale) { if(drawingPanel!=null) { drawingPanel.setAutoscaleX(autoscale); } } /** * Determines if the panel's x axis autoscale property is true. * @return <code>true<\code> if autoscaled. */ public boolean isAutoscaleX() { if(drawingPanel!=null) { return drawingPanel.isAutoscaleX(); } return false; } /** * Autoscale the y axis using min and max values. * from measurable objects. * @param autoscale */ public void setAutoscaleY(boolean autoscale) { if(drawingPanel!=null) { drawingPanel.setAutoscaleY(autoscale); } } /** * Determines if the y axis autoscale property is true. * @return <code>true<\code> if autoscaled. */ public boolean isAutoscaleY() { if(drawingPanel!=null) { return drawingPanel.isAutoscaleY(); } return false; } /** * Sets the aspect ratio for horizontal to vertical to unity when <code>true<\code>. * @param isSquare boolean */ public void setSquareAspect(boolean isSquare) { if(drawingPanel!=null) { drawingPanel.setSquareAspect(isSquare); } } /** * Sets Cartesian axes to log scale. * * @param logX * @param logY */ public void setLogScale(boolean logX, boolean logY) { if((drawingPanel!=null)&&(drawingPanel instanceof PlottingPanel)) { ((PlottingPanel) drawingPanel).setLogScale(logX, logY); } } /** * Sets the scale using pixels per unit. * * @param enable boolean enable fixed pixels per unit * @param xPixPerUnit double * @param yPixPerUnit double */ public void setPixelsPerUnit(boolean enable, double xPixPerUnit, double yPixPerUnit) { drawingPanel.setPixelsPerUnit(enable, xPixPerUnit, yPixPerUnit); } /** * Sets the drawing panel's preferred scale. * @param xmin * @param xmax * @param ymin * @param ymax */ public void setPreferredMinMax(double xmin, double xmax, double ymin, double ymax) { if(drawingPanel!=null) { drawingPanel.setPreferredMinMax(xmin, xmax, ymin, ymax); } } /** * Sets the drawing panel's preferred scale in the vertical direction. * @param ymin * @param ymax */ public void setPreferredMinMaxY(double ymin, double ymax) { if(drawingPanel!=null) { drawingPanel.setPreferredMinMaxY(ymin, ymax); } } /** * Sets the drawing panel's preferred scale in the horizontal direction. * @param xmin the minimum value * @param xmax the maximum value */ public void setPreferredMinMaxX(double xmin, double xmax) { if(drawingPanel!=null) { drawingPanel.setPreferredMinMaxX(xmin, xmax); } } /** * Clears data and repaints the drawing panel within this frame. */ public void clearDataAndRepaint() { clearData(); drawingPanel.repaint(); } /** * Clears Drawable objects added by the user from this frame. */ public void clearDrawables() { drawingPanel.clear(); // removes all drawables } /** * Adds a drawable object to the frame's drawing panel. * @param drawable */ public synchronized void addDrawable(Drawable drawable) { if(drawingPanel!=null) { drawingPanel.addDrawable(drawable); } } /** * Replaces a Drawable object with another Drawable. * * @param oldDrawable Drawable * @param newDrawable Drawable */ public synchronized void replaceDrawable(Drawable oldDrawable, Drawable newDrawable) { if(drawingPanel!=null) { drawingPanel.replaceDrawable(oldDrawable, newDrawable); } } /** * Removes a drawable object to the frame's drawing panel. * @param drawable */ public synchronized void removeDrawable(Drawable drawable) { if(drawingPanel!=null) { drawingPanel.removeDrawable(drawable); } } /** * Shows a message in a yellow text box in the lower right hand corner. * * @param msg */ public void setMessage(String msg) { drawingPanel.setMessage(msg); } /** * Shows a message in a yellow text box at the given location. * * location 0=bottom left * location 1=bottom right * location 2=top right * location 3=top left * * @param msg * @param location */ public void setMessage(String msg, int location) { drawingPanel.setMessage(msg, location); } /** * Gets objects of a specific class from the drawing panel. * * Assignable subclasses are NOT returned. Interfaces CANNOT be specified. * The same objects will be in the drawable list and the cloned list. * * @param c the class of the object * * @return the list */ public synchronized <T extends Drawable> ArrayList<T> getObjectOfClass(Class<T> c) { if(drawingPanel!=null) { return drawingPanel.getObjectOfClass(c); } return null; } /** * Gets Drawable previously objects added by the user. * * @return the list */ public synchronized ArrayList<Drawable> getDrawables() { if(drawingPanel!=null) { return drawingPanel.getDrawables(); } return new ArrayList<Drawable>(); // return an empty list } public DrawableAxes getAxes() { if(drawingPanel instanceof PlottingPanel) { return((PlottingPanel) drawingPanel).getAxes(); } return null; } /** * Gets Drawable objects added by the user of an assignable type. The list contains * objects that are assignable from the class or interface. * * @param c the type of Drawable object * * @return the cloned list * * @see #getObjectOfClass(Class c) */ public synchronized <T extends Drawable> ArrayList<T> getDrawables(Class<T> c) { if(drawingPanel!=null) { return drawingPanel.getDrawables(c); } return new ArrayList<T>(); // return an empty list } /** * Removes all objects of the given class from the drawable list. * * Assignable subclasses are NOT removed. Interfaces CANNOT be specified. * * @param c the class */ public synchronized <T extends Drawable> void removeObjectsOfClass(Class<T> c) { drawingPanel.removeObjectsOfClass(c); } /** * Sets the interactive mouse handler if the drawing panel is an interactive panel. * * Throws an invalid cast exception if the panel is not of the correct type. * * @param handler the mouse handler */ public void setInteractiveMouseHandler(InteractiveMouseHandler handler) { ((InteractivePanel) drawingPanel).setInteractiveMouseHandler(handler); } /** * Adds the drawing panel to the the frame. The panel is added to the center * of the frame's content pane. * * @param _drawingPanel */ public void setDrawingPanel(DrawingPanel _drawingPanel) { if(drawingPanel!=null) { // remove the old drawing panel. getContentPane().remove(drawingPanel); } drawingPanel = _drawingPanel; if(drawingPanel!=null) { getContentPane().add(drawingPanel, BorderLayout.CENTER); } } /** * Sets the interior background color for the current drawing panel. * The interior of a PlottingaPanel is the area inside the axes where is displayed. * The interior of a DrawingPanel is the entire panel. */ public void setInteriorBackground(Color color) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).getAxes().setInteriorBackground(color); } else { drawingPanel.setBackground(color); } } /** * This is a hack to fix a bug when the reload button is pressed in browsers * running JDK 1.4. * * @param g */ public void paint(Graphics g) { if(!OSPRuntime.appletMode) { super.paint(g); return; } try { super.paint(g); } catch(Exception ex) { System.err.println("OSPFrame paint error: "+ex.toString()); //$NON-NLS-1$ System.err.println("Title: "+this.getTitle()); //$NON-NLS-1$ } } /** * Enables the paste edit menu item. * @param enable boolean */ public void setEnabledPaste(boolean enable) { pasteItem.setEnabled(enable); } /** * Pastes drawables found in the specified xml control. * * @param control the xml control */ protected void pasteAction(XMLControlElement control) { // get Drawables using an xml tree chooser XMLTreeChooser chooser = new XMLTreeChooser(DisplayRes.getString("DrawingFrame.SelectDrawables_chooser_title"), DisplayRes.getString("DrawingFrame.SelectDrawables_chooser_message"), this); //$NON-NLS-1$ //$NON-NLS-2$ java.util.List<XMLProperty> props = chooser.choose(control, Drawable.class); if(!props.isEmpty()) { Iterator<XMLProperty> it = props.iterator(); while(it.hasNext()) { XMLControl prop = (XMLControl) it.next(); Drawable drawable = (Drawable) prop.loadObject(null); addDrawable(drawable); } } drawingPanel.repaint(); } /** * Enables the replace edit menu item. * @param enable boolean */ public void setEnabledReplace(boolean enable) { replaceItem.setEnabled(enable); } /** * Replaces the drawables with the drawables found in the specified XML control. * @param control XMLControlElement */ public void replaceAction(XMLControlElement control) { clearDrawables(); pasteAction(control); } /** * Copies objects found in the specified xml control. * * @param control the xml control */ protected void copyAction(XMLControlElement control) { StringSelection data = new StringSelection(control.toXML()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, this); } /** * Implementation of ClipboardOwner interface. * * Override this method to receive notification that data copied to the clipboard has changed. * * @param clipboard Clipboard * @param contents Transferable */ public void lostOwnership(Clipboard clipboard, Transferable contents) {} /** * Enables the copy edit menu item. * @param enable boolean */ public void setEnabledCopy(boolean enable) { copyItem.setEnabled(enable); } protected void refreshGUI() { createMenuBar(); addMenuItems(); pack(); } /** * Adds Views menu items on the menu bar. * Override this method to add custom menu items. */ protected void addMenuItems() {} /** * Creates a standard DrawingFrame menu bar and adds it to the frame. */ private void createMenuBar() { JMenuBar menuBar = new JMenuBar(); fileMenu = new JMenu(DisplayRes.getString("DrawingFrame.File_menu_item")); //$NON-NLS-1$ JMenu printMenu = new JMenu(DisplayRes.getString("DrawingFrame.Print_menu_title")); //$NON-NLS-1$ JMenuItem printItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Print_menu_item")); //$NON-NLS-1$ printMenu.add(printItem); printItem.setAccelerator(KeyStroke.getKeyStroke('P', MENU_SHORTCUT_KEY_MASK)); printItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PrintUtils.printComponent(drawingPanel); } }); JMenuItem printFrameItem = new JMenuItem(DisplayRes.getString("DrawingFrame.PrintFrame_menu_item")); //$NON-NLS-1$ printMenu.add(printFrameItem); printFrameItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PrintUtils.printComponent(DrawingFrame.this); } }); JMenuItem saveXMLItem = new JMenuItem(DisplayRes.getString("DrawingFrame.SaveXML_menu_item")); //$NON-NLS-1$ saveXMLItem.setAccelerator(KeyStroke.getKeyStroke('S', MENU_SHORTCUT_KEY_MASK)); saveXMLItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveXML(); } }); //ExportTool menu item /* JMenuItem exportItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Export_menu_item")); //$NON-NLS-1$ exportItem.setAccelerator(KeyStroke.getKeyStroke('E', MENU_SHORTCUT_KEY_MASK)); exportItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { ExportTool.getTool().send(new LocalJob(drawingPanel), null); } catch(RemoteException ex) {} } });*/ // create export tool menu item if the tool exists in classpath JMenuItem exportItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Export_menu_item")); //$NON-NLS-1$ exportItem.setAccelerator(KeyStroke.getKeyStroke('E', MENU_SHORTCUT_KEY_MASK)); Class<?> exportTool = null; if(OSPRuntime.loadExportTool) { try { exportTool = Class.forName("org.opensourcephysics.tools.ExportTool"); //$NON-NLS-1$ } catch(Exception ex) { OSPRuntime.loadExportTool = false; OSPLog.finest("Cannot instantiate data export tool class:\n"+ex.toString()); //$NON-NLS-1$ exportItem.setEnabled(false); } } final Class<?> tool = exportTool; exportItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Method m = tool.getMethod("getTool", (Class[]) null); //$NON-NLS-1$ Tool tool = (Tool) m.invoke(null, (Object[]) null); tool.send(new LocalJob(drawingPanel), reply); } catch(Exception ex) {} } }); //Save menu item JMenu saveImage = new JMenu(DisplayRes.getString("DrawingFrame.SaveImage_menu_title")); //$NON-NLS-1$ JMenuItem epsMenuItem = new JMenuItem(DisplayRes.getString("DrawingFrame.EPS_menu_item")); //$NON-NLS-1$ JMenuItem jpegMenuItem = new JMenuItem(DisplayRes.getString("DrawingFrame.JPEG_menu_item")); //$NON-NLS-1$ JMenuItem pngMenuItem = new JMenuItem(DisplayRes.getString("DrawingFrame.PNG_menu_item")); //$NON-NLS-1$ saveImage.add(epsMenuItem); saveImage.add(jpegMenuItem); saveImage.add(pngMenuItem); epsMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { GUIUtils.saveImage(drawingPanel, "eps", DrawingFrame.this); //$NON-NLS-1$ } }); jpegMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { GUIUtils.saveImage(drawingPanel, "jpeg", DrawingFrame.this); //$NON-NLS-1$ } }); pngMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { GUIUtils.saveImage(drawingPanel, "png", DrawingFrame.this); //$NON-NLS-1$ } }); JMenuItem inspectItem = new JMenuItem(DisplayRes.getString("DrawingFrame.InspectMenuItem")); //$NON-NLS-1$ inspectItem.setAccelerator(KeyStroke.getKeyStroke('I', MENU_SHORTCUT_KEY_MASK)); inspectItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { inspectXML(); // cannot use a static method here because of run-time binding } }); if(OSPRuntime.applet==null) { fileMenu.add(printMenu); fileMenu.add(saveXMLItem); fileMenu.add(exportItem); fileMenu.add(saveImage); } fileMenu.add(inspectItem); menuBar.add(fileMenu); // edit menu editMenu = new JMenu(DisplayRes.getString("DrawingFrame.Edit_menu_title")); //$NON-NLS-1$ menuBar.add(editMenu); copyItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Copy_menu_item")); //$NON-NLS-1$ copyItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { XMLControlElement control = new XMLControlElement(DrawingFrame.this); control.saveObject(null); copyAction(control); } }); editMenu.add(copyItem); pasteItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Paste_menu_item")); //$NON-NLS-1$ pasteItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable data = clipboard.getContents(null); XMLControlElement control = new XMLControlElement(); control.readXML((String) data.getTransferData(DataFlavor.stringFlavor)); pasteAction(control); } catch(UnsupportedFlavorException ex) {} catch(IOException ex) {} catch(HeadlessException ex) {} } }); pasteItem.setEnabled(false); // not supported yet editMenu.add(pasteItem); replaceItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Replace_menu_item")); //$NON-NLS-1$ replaceItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable data = clipboard.getContents(null); XMLControlElement control = new XMLControlElement(); control.readXML((String) data.getTransferData(DataFlavor.stringFlavor)); replaceAction(control); } catch(UnsupportedFlavorException ex) {} catch(IOException ex) {} catch(HeadlessException ex) {} } }); replaceItem.setEnabled(false); // not supported yet editMenu.add(replaceItem); setJMenuBar(menuBar); // additonal menus loadDisplayMenu(); loadToolsMenu(); //help menu JMenu helpMenu = new JMenu(DisplayRes.getString("DrawingFrame.Help_menu_item")); //$NON-NLS-1$ menuBar.add(helpMenu); JMenuItem aboutItem = new JMenuItem(DisplayRes.getString("DrawingFrame.AboutOSP_menu_item")); //$NON-NLS-1$ aboutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { OSPRuntime.showAboutDialog(DrawingFrame.this); } }); helpMenu.add(aboutItem); } /** * Adds a Display menu to the menu bar. */ protected JMenu loadDisplayMenu() { JMenuBar menuBar = getJMenuBar(); if(menuBar==null) { return null; } JMenu displayMenu = new JMenu(DisplayRes.getString("DrawingFrame.Display_menu_title")); //$NON-NLS-1$ menuBar.add(displayMenu); JMenu fontMenu = new JMenu(DisplayRes.getString("DrawingFrame.Font_menu_title")); //$NON-NLS-1$ displayMenu.add(fontMenu); JMenuItem sizeUpItem = new JMenuItem(DisplayRes.getString("DrawingFrame.IncreaseFontSize_menu_item")); //$NON-NLS-1$ sizeUpItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FontSizer.levelUp(); } }); fontMenu.add(sizeUpItem); final JMenuItem sizeDownItem = new JMenuItem(DisplayRes.getString("DrawingFrame.DecreaseFontSize_menu_item")); //$NON-NLS-1$ sizeDownItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FontSizer.levelDown(); } }); fontMenu.add(sizeDownItem); fontMenu.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { sizeDownItem.setEnabled(FontSizer.getLevel()>0); } }); JMenu aliasMenu = new JMenu(DisplayRes.getString("DrawingFrame.AntiAlias_menu_title")); //$NON-NLS-1$ displayMenu.add(aliasMenu); final JCheckBoxMenuItem textAliasItem = new JCheckBoxMenuItem(DisplayRes.getString("DrawingFrame.Text_checkbox_label"), false); //$NON-NLS-1$ textAliasItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.antialiasTextOn = textAliasItem.isSelected(); drawingPanel.repaint(); } }); aliasMenu.add(textAliasItem); final JCheckBoxMenuItem shapeAliasItem = new JCheckBoxMenuItem(DisplayRes.getString("DrawingFrame.Drawing_textbox_label"), false); //$NON-NLS-1$ shapeAliasItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.antialiasShapeOn = shapeAliasItem.isSelected(); drawingPanel.repaint(); } }); aliasMenu.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { textAliasItem.setSelected(drawingPanel.antialiasTextOn); shapeAliasItem.setSelected(drawingPanel.antialiasShapeOn); } }); aliasMenu.add(shapeAliasItem); menuBar.add(displayMenu); return displayMenu; } /** * Adds a Tools menu to the menu bar. */ protected JMenu loadToolsMenu() { JMenuBar menuBar = getJMenuBar(); if(menuBar==null) { return null; } // create Tools menu item JMenu toolsMenu = new JMenu(DisplayRes.getString("DrawingFrame.Tools_menu_title")); //$NON-NLS-1$ menuBar.add(toolsMenu); // create Data Tool menu item if the tool exists in the classpath JMenuItem datasetItem = new JMenuItem(DisplayRes.getString("DrawingFrame.DatasetTool_menu_item")); //$NON-NLS-1$ toolsMenu.add(datasetItem); Class<?> datasetToolClass = null; if(OSPRuntime.loadDataTool) { try { datasetToolClass = Class.forName("org.opensourcephysics.tools.DataTool"); //$NON-NLS-1$ } catch(Exception ex) { OSPLog.finest("Cannot instantiate data analysis tool class:\n"+ex.toString()); //$NON-NLS-1$ OSPRuntime.loadDataTool = false; datasetItem.setEnabled(false); } } final Class<?> finalDatasetToolClass = datasetToolClass; // class must be final for action listener datasetItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Method m = finalDatasetToolClass.getMethod("getTool", (Class[]) null); //$NON-NLS-1$ Tool tool = (Tool) m.invoke(null, (Object[]) null); tool.send(new LocalJob(drawingPanel), reply); if(tool instanceof OSPFrame) { ((OSPFrame) tool).setKeepHidden(false); } ((JFrame) tool).setVisible(true); } catch(Exception ex) {} } }); // create Fourier Tool menu item if the tool exists in the classpath JMenuItem fourierToolItem = new JMenuItem(DisplayRes.getString("DrawingFrame.FourierTool_menu_item")); //$NON-NLS-1$ toolsMenu.add(fourierToolItem); Class<?> fourierToolClass = null; if(OSPRuntime.loadFourierTool) { try { fourierToolClass = Class.forName("org.opensourcephysics.tools.FourierTool"); //$NON-NLS-1$ } catch(Exception ex) { OSPLog.finest("Cannot instantiate Fourier analysis tool class:\n"+ex.toString()); //$NON-NLS-1$ OSPRuntime.loadFourierTool = false; fourierToolItem.setEnabled(false); } } final Class<?> finalFourierToolClass = fourierToolClass; // class must be final for action listener fourierToolItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Method m = finalFourierToolClass.getMethod("getTool", (Class[]) null); //$NON-NLS-1$ Tool tool = (Tool) m.invoke(null, (Object[]) null); tool.send(new LocalJob(drawingPanel), reply); if(tool instanceof OSPFrame) { ((OSPFrame) tool).setKeepHidden(false); } ((JFrame) tool).setVisible(true); } catch(Exception ex) {} } }); // create snapshot menu item JMenuItem snapshotItem = new JMenuItem(DisplayRes.getString("DisplayPanel.Snapshot_menu_item")); //$NON-NLS-1$ if(OSPRuntime.applet==null) { toolsMenu.add(snapshotItem); } snapshotItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SnapshotTool tool = SnapshotTool.getTool(); if(drawingPanel!=null) { tool.saveImage(null, drawingPanel); } else { tool.saveImage(null, getContentPane()); } } }); // create video capture menu item JMenuItem videoItem = new JMenuItem(DisplayRes.getString("DrawingFrame.MenuItem.Capture")); //$NON-NLS-1$ if(OSPRuntime.applet==null) { toolsMenu.add(videoItem); } Class<?> videoToolClass = null; if(OSPRuntime.loadVideoTool) { try { videoToolClass = Class.forName("org.opensourcephysics.tools.VideoCaptureTool"); //$NON-NLS-1$ } catch(Exception ex) { OSPRuntime.loadVideoTool = false; OSPLog.finest("Cannot instantiate video capture tool class:\n"+ex.toString()); //$NON-NLS-1$ videoItem.setEnabled(false); } } final Class<?> finalVideoToolClass = videoToolClass; // class must be final for action listener videoItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(drawingPanel.getVideoTool()==null) { try { Method m = finalVideoToolClass.getMethod("getTool", (Class[]) null); //$NON-NLS-1$ Tool tool = (Tool) m.invoke(null, (Object[]) null); // tool is a VideoTool drawingPanel.setVideoTool((VideoTool) tool); ((VideoTool) tool).setVisible(true); ((VideoTool) tool).clear(); } catch(Exception ex) { OSPLog.finest("Cannot perform action to get video tool class:\n"+ex.toString()); //$NON-NLS-1$ } } else { drawingPanel.getVideoTool().setVisible(true); } } }); return toolsMenu; } /** * Sets a custom properties inspector window. * * @param w the new inspector window */ public void setCustomInspector(Window w) { if(customInspector!=null) { customInspector.setVisible(false); // hide the current inspector window } customInspector = w; } /** * Inspects the drawing frame by using an xml document tree. */ public void inspectXML() { if(customInspector!=null) { customInspector.setVisible(true); return; } XMLControlElement xml = null; try { // if drawingPanel provides an xml loader, inspect the drawingPanel Method method = drawingPanel.getClass().getMethod("getLoader", (Class[]) null); //$NON-NLS-1$ if((method!=null)&&Modifier.isStatic(method.getModifiers())) { xml = new XMLControlElement(drawingPanel); } } catch(NoSuchMethodException ex) { // this drawing panel cannot be inspected return; } // display a TreePanel in a modal dialog XMLTreePanel treePanel = new XMLTreePanel(xml); JDialog dialog = new JDialog((java.awt.Frame) null, true); dialog.setContentPane(treePanel); dialog.setSize(new Dimension(600, 300)); dialog.setVisible(true); } public void saveXML() { JFileChooser chooser = OSPRuntime.getChooser(); int result = chooser.showSaveDialog(null); if(result==JFileChooser.APPROVE_OPTION) { OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString(); File file = chooser.getSelectedFile(); // check to see if file already exists if(file.exists()) { int selected = JOptionPane.showConfirmDialog(null, DisplayRes.getString("DrawingFrame.ReplaceExisting_message")+file.getName() //$NON-NLS-1$ +DisplayRes.getString("DrawingFrame.QuestionMark"), //$NON-NLS-1$ DisplayRes.getString("DrawingFrame.ReplaceFile_option_title"), //$NON-NLS-1$ JOptionPane.YES_NO_CANCEL_OPTION); if(selected!=JOptionPane.YES_OPTION) { return; } } String fileName = XML.getRelativePath(file.getAbsolutePath()); if((fileName==null)||fileName.trim().equals("")) { //$NON-NLS-1$ return; } int i = fileName.toLowerCase().lastIndexOf(".xml"); //$NON-NLS-1$ if(i!=fileName.length()-4) { fileName += ".xml"; //$NON-NLS-1$ } try { // if drawingPanel provides an xml loader, save the drawingPanel Method method = drawingPanel.getClass().getMethod("getLoader", (Class[]) null); //$NON-NLS-1$ if((method!=null)&&Modifier.isStatic(method.getModifiers())) { XMLControl xml = new XMLControlElement(drawingPanel); xml.write(fileName); } } catch(NoSuchMethodException ex) { // this drawingPanel cannot be saved return; } } } /** * Returns an XML.ObjectLoader to save and load data for this program. * * @return the object loader */ public static XML.ObjectLoader getLoader() { return new DrawingFrameLoader(); } static protected class DrawingFrameLoader implements XML.ObjectLoader { /** * createObject * * @param control XMLControl * @return Object */ public Object createObject(XMLControl control) { DrawingFrame frame = new DrawingFrame(); frame.setTitle(control.getString("title")); //$NON-NLS-1$ frame.setLocation(control.getInt("location x"), control.getInt("location y")); //$NON-NLS-1$ //$NON-NLS-2$ frame.setSize(control.getInt("width"), control.getInt("height")); //$NON-NLS-1$ //$NON-NLS-2$ if(control.getBoolean("showing")) { //$NON-NLS-1$ frame.setVisible(true); } return frame; } /** * Save data object's data in the control. * * @param control XMLControl * @param obj Object */ public void saveObject(XMLControl control, Object obj) { DrawingFrame frame = (DrawingFrame) obj; control.setValue("title", frame.getTitle()); //$NON-NLS-1$ control.setValue("showing", frame.isShowing()); //$NON-NLS-1$ control.setValue("location x", frame.getLocation().x); //$NON-NLS-1$ control.setValue("location y", frame.getLocation().y); //$NON-NLS-1$ control.setValue("width", frame.getSize().width); //$NON-NLS-1$ control.setValue("height", frame.getSize().height); //$NON-NLS-1$ control.setValue("drawing panel", frame.getDrawingPanel()); //$NON-NLS-1$ } /** * Loads the object with data from the control. * * @param control XMLControl * @param obj Object * @return Object */ public Object loadObject(XMLControl control, Object obj) { DrawingFrame frame = ((DrawingFrame) obj); DrawingPanel panel = frame.getDrawingPanel(); panel.clear(); XMLControl panelControl = control.getChildControl("drawing panel"); //$NON-NLS-1$ panelControl.loadObject(panel); panel.repaint(); frame.setTitle(control.getString("title")); //$NON-NLS-1$ frame.setLocation(control.getInt("location x"), control.getInt("location y")); //$NON-NLS-1$ //$NON-NLS-2$ frame.setSize(control.getInt("width"), control.getInt("height")); //$NON-NLS-1$ //$NON-NLS-2$ if(control.getBoolean("showing")) { //$NON-NLS-1$ frame.setVisible(true); } return obj; } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */