/* * 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.ejs.control; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.TextArea; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Locale; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JRadioButtonMenuItem; import javax.swing.JRootPane; import javax.swing.KeyStroke; import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.SwingPropertyChangeSupport; import org.opensourcephysics.controls.Animation; import org.opensourcephysics.controls.Calculation; import org.opensourcephysics.controls.ControlUtils; import org.opensourcephysics.controls.MainFrame; import org.opensourcephysics.controls.OSPApplication; import org.opensourcephysics.controls.OSPLog; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.controls.XMLControlElement; import org.opensourcephysics.controls.XMLTreePanel; import org.opensourcephysics.display.Dataset; import org.opensourcephysics.display.DatasetManager; import org.opensourcephysics.display.DisplayRes; import org.opensourcephysics.display.DrawingPanel; import org.opensourcephysics.display.GUIUtils; import org.opensourcephysics.display.Hidable; import org.opensourcephysics.display.OSPFrame; import org.opensourcephysics.display.OSPRuntime; import org.opensourcephysics.display.PrintUtils; import org.opensourcephysics.ejs.EjsRes; 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.ToolsRes; import org.opensourcephysics.tools.VideoTool; /** * EjsControlFrame defines an Easy Java Simulations control that is guaranteed to have a * parent frame. * * @author Wolfgang Christian * @version 1.0 */ public class EjsControlFrame extends ParsedEjsControl implements RootPaneContainer, MainFrame { final static int MENU_SHORTCUT_KEY_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); protected Tool reply; protected JMenuItem[] languageItems; protected JMenuItem translateItem, snapshotItem, videoItem, clearItem; protected JMenu languageMenu; EjsFrame mainFrame = new EjsFrame(); DrawingPanel defaultDrawingPanel; protected JFrame messageFrame = new JFrame(EjsRes.getString("EjsControlFrame.Messages_frame_title")); //$NON-NLS-1$ TextArea messageArea = new TextArea(20, 20); Object model; JMenuBar menuBar; volatile protected XMLControlElement xmlDefault = null; protected PropertyChangeSupport support = new SwingPropertyChangeSupport(this); /** * Constructor EjsControlFrame * * @param _simulation */ public EjsControlFrame(Object _simulation) { this(_simulation, "name=controlFrame;title=Control Frame;location=400,0;layout=border;exit=false; visible=true"); //$NON-NLS-1$ } /** * Constructor EjsControlFrame * * @param _simulation * @param param */ public EjsControlFrame(Object _simulation, String param) { super(_simulation); mainFrame.addChildFrame(messageFrame); model = _simulation; mainFrame.setName("controlFrame"); //$NON-NLS-1$ addObject(mainFrame, "Frame", param); //$NON-NLS-1$ createMenuBar(); if(OSPRuntime.appletMode) { mainFrame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); } messageFrame.getContentPane().add(messageArea); messageFrame.setSize(300, 175); // responds to data from the DatasetTool reply = new Tool() { public void send(Job job, Tool replyTo) throws RemoteException { if(defaultDrawingPanel==null) { return; } XMLControlElement control = new XMLControlElement(); try { control.readXML(job.getXML()); } catch(RemoteException ex) {} ArrayList<?> datasets = defaultDrawingPanel.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; } } } defaultDrawingPanel.repaint(); } }; } /** * Adds a child frame that depends on the main frame. * Child frames are closed when this frame is closed. * * @param mainFrame JFrame */ public void addChildFrame(JFrame child) { if((mainFrame==null)||(child==null)) { return; } mainFrame.addChildFrame(child); } /** * Clears the child frames from the main frame. */ public void clearChildFrames() { if(mainFrame==null) { return; } mainFrame.clearChildFrames(); } /** * Gets a copy of the ChildFrames collection. * @return Collection */ public Collection<JFrame> getChildFrames() { return mainFrame.getChildFrames(); } /** * Gets the OSPFrame that contains the control. * * @return */ public OSPFrame getMainFrame() { return mainFrame; } /** * Gets the OSPFrame that contains the control. Replaced by getMainFrame to implement MainFrame interface. * @deprecated * @return */ public OSPFrame getFrame() { return mainFrame; } private void createMenuBar() { menuBar = new JMenuBar(); mainFrame.setJMenuBar(menuBar); JMenu fileMenu = new JMenu(EjsRes.getString("EjsControlFrame.File_menu")); //$NON-NLS-1$ if(OSPRuntime.applet==null) { menuBar.add(fileMenu); } JMenuItem readItem = new JMenuItem(EjsRes.getString("EjsControlFrame.Read_menu_item")); //$NON-NLS-1$ clearItem = new JMenuItem(EjsRes.getString("EjsControlFrame.Clear_menu_item")); //$NON-NLS-1$ clearItem.setEnabled(false); JMenuItem saveAsItem = new JMenuItem(EjsRes.getString("EjsControlFrame.SaveAs_menu_item")); //$NON-NLS-1$ JMenuItem inspectItem = new JMenuItem(EjsRes.getString("EjsControlFrame.Inspect_menu_item")); //$NON-NLS-1$ JMenuItem printFrameItem = new JMenuItem(DisplayRes.getString("DrawingFrame.PrintFrame_menu_item")); //$NON-NLS-1$ JMenuItem saveFrameAsEPSItem = new JMenuItem(DisplayRes.getString("DrawingFrame.SaveFrameAsEPS_menu_item")); //$NON-NLS-1$ JMenu printMenu = new JMenu(DisplayRes.getString("DrawingFrame.Print_menu_title")); //$NON-NLS-1$ fileMenu.add(readItem); fileMenu.add(saveAsItem); fileMenu.add(inspectItem); fileMenu.add(clearItem); fileMenu.add(printMenu); printMenu.add(printFrameItem); printMenu.add(saveFrameAsEPSItem); readItem.setAccelerator(KeyStroke.getKeyStroke('R', MENU_SHORTCUT_KEY_MASK)); readItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // readParameters(); // cannot use a static method here because of run-time binding loadXML((String) null); support.firePropertyChange("xmlDefault", null, xmlDefault); //$NON-NLS-1$ mainFrame.repaint(); } }); clearItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { clearDefaultXML(); } }); saveAsItem.setAccelerator(KeyStroke.getKeyStroke('S', MENU_SHORTCUT_KEY_MASK)); saveAsItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveXML(); } }); inspectItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { inspectXML(); // cannot use a static method here because of run-time binding } }); // print item printFrameItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PrintUtils.printComponent(mainFrame); } }); // save as EPS item saveFrameAsEPSItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { PrintUtils.saveComponentAsEPS(mainFrame); } catch(IOException ex) {} } }); loadDisplayMenu(); loadToolsMenu(); //help menu JMenu helpMenu = new JMenu(EjsRes.getString("EjsControlFrame.Help_menu")); //$NON-NLS-1$ menuBar.add(helpMenu); JMenuItem aboutItem = new JMenuItem(EjsRes.getString("EjsControlFrame.About_menu_item")); //$NON-NLS-1$ aboutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { OSPRuntime.showAboutDialog(EjsControlFrame.this.getMainFrame()); } }); helpMenu.add(aboutItem); JMenuItem sysItem = new JMenuItem(EjsRes.getString("EjsControlFrame.System_menu_item")); //$NON-NLS-1$ sysItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ControlUtils.showSystemProperties(true); } }); helpMenu.add(sysItem); helpMenu.addSeparator(); JMenuItem logToFileItem = new JCheckBoxMenuItem(EjsRes.getString("EjsControlFrame.LogToFile_check_box")); //$NON-NLS-1$ logToFileItem.setSelected(false); logToFileItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getSource(); if(OSPRuntime.appletMode||(OSPRuntime.applet!=null)) { return; // applets cannot log to file } OSPLog.getOSPLog().setLogToFile(item.isSelected()); } }); if(OSPRuntime.applet==null) { helpMenu.add(logToFileItem); } JMenuItem logItem = new JMenuItem(EjsRes.getString("EjsControlFrame.MessageLog_menu_item")); //$NON-NLS-1$ logItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { OSPLog.showLog(); } }); helpMenu.add(logItem); menuBar.add(helpMenu); } /** * Adds a Tools menu to the menu bar. */ protected JMenu loadToolsMenu() { JMenuBar menuBar = mainFrame.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 dataset tool menu item if the tool exists in 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(ClassNotFoundException ex) { OSPRuntime.loadDataTool = false; OSPLog.finest("Cannot instantiate data analysis tool class:\n"+ex.toString()); //$NON-NLS-1$ 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(defaultDrawingPanel), reply); if(tool instanceof OSPFrame) { ((OSPFrame) tool).setKeepHidden(false); } ((JFrame) tool).setVisible(true); } catch(Exception ex) { System.out.println(ex); } } }); // create snapshot menu item snapshotItem = new JMenuItem(DisplayRes.getString("DisplayPanel.Snapshot_menu_item")); //$NON-NLS-1$ snapshotItem.setEnabled(false); if(OSPRuntime.applet==null) { toolsMenu.add(snapshotItem); } snapshotItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SnapshotTool tool = SnapshotTool.getTool(); if(defaultDrawingPanel!=null) { tool.saveImage(null, defaultDrawingPanel); } 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(ClassNotFoundException 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(defaultDrawingPanel.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 defaultDrawingPanel.setVideoTool((VideoTool) tool); ((VideoTool) tool).setVisible(true); ((VideoTool) tool).clear(); } catch(Exception ex) {} } else { defaultDrawingPanel.getVideoTool().setVisible(true); } } }); return toolsMenu; } /** * Adds a Display menu to the menu bar. */ protected void loadDisplayMenu() { JMenu displayMenu = new JMenu(); displayMenu.setText(EjsRes.getString("EjsControlFrame.Display_menu")); //$NON-NLS-1$ menuBar.add(displayMenu); // language menu languageMenu = new JMenu(); languageMenu.setText(EjsRes.getString("EjsControlFrame.Language")); //$NON-NLS-1$ translateItem = new JMenuItem(); translateItem.setText(EjsRes.getString("EjsControlFrame.Translate")); //$NON-NLS-1$ // added by D Brown 2007-10-17 if(OSPRuntime.getTranslator()!=null) { translateItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { OSPRuntime.getTranslator().showProperties(model.getClass()); if(OSPRuntime.getTranslator() instanceof Hidable) { ((Hidable) OSPRuntime.getTranslator()).setKeepHidden(false); } OSPRuntime.getTranslator().setVisible(true); } }); } translateItem.setEnabled(OSPRuntime.getTranslator()!=null); languageMenu.add(translateItem, 0); final Locale[] locales = OSPRuntime.getInstalledLocales(); Action languageAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { String language = e.getActionCommand(); OSPLog.finest("setting language to "+language); //$NON-NLS-1$ for(int i = 0; i<locales.length; i++) { if(language.equals(locales[i].getDisplayName())) { ToolsRes.setLocale(locales[i]); return; } } } }; ButtonGroup languageGroup = new ButtonGroup(); languageItems = new JMenuItem[locales.length]; for(int i = 0; i<locales.length; i++) { languageItems[i] = new JRadioButtonMenuItem(locales[i].getDisplayName(locales[i])); languageItems[i].setActionCommand(locales[i].getDisplayName()); languageItems[i].addActionListener(languageAction); languageMenu.add(languageItems[i]); languageGroup.add(languageItems[i]); } for(int i = 0; i<locales.length; i++) { if(locales[i].getLanguage().equals(ToolsRes.getLanguage())) { languageItems[i].setSelected(true); } } displayMenu.add(languageMenu); JMenu fontMenu = new JMenu(EjsRes.getString("EjsControlFrame.Font_menu")); //$NON-NLS-1$ displayMenu.add(fontMenu); JMenuItem sizeUpItem = new JMenuItem(); sizeUpItem.setText(EjsRes.getString("EjsControlFrame.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(); sizeDownItem.setText(EjsRes.getString("EjsControlFrame.DecreaseFontSize_menu_item")); //$NON-NLS-1$ sizeDownItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FontSizer.levelDown(); } }); fontMenu.add(sizeDownItem); JMenu aliasMenu = new JMenu(EjsRes.getString("EjsControlFrame.AntiAlias_menu")); //$NON-NLS-1$ displayMenu.add(aliasMenu); final JCheckBoxMenuItem textAliasItem = new JCheckBoxMenuItem(EjsRes.getString("EjsControlFrame.Text_check_box"), //$NON-NLS-1$ false); textAliasItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { defaultDrawingPanel.setAntialiasTextOn(textAliasItem.isSelected()); defaultDrawingPanel.repaint(); } }); aliasMenu.add(textAliasItem); final JCheckBoxMenuItem shapeAliasItem = new JCheckBoxMenuItem(EjsRes.getString("EjsControlFrame.Drawing_check_box"), false); //$NON-NLS-1$ shapeAliasItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { defaultDrawingPanel.setAntialiasShapeOn(shapeAliasItem.isSelected()); defaultDrawingPanel.repaint(); } }); fontMenu.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { sizeDownItem.setEnabled(FontSizer.getLevel()>0); } }); aliasMenu.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if(defaultDrawingPanel==null) { textAliasItem.setEnabled(false); shapeAliasItem.setEnabled(false); } else { textAliasItem.setEnabled(true); textAliasItem.setEnabled(true); textAliasItem.setSelected(defaultDrawingPanel.isAntialiasTextOn()); shapeAliasItem.setSelected(defaultDrawingPanel.isAntialiasShapeOn()); } } }); aliasMenu.add(shapeAliasItem); menuBar.add(displayMenu); ToolsRes.addPropertyChangeListener("locale", new PropertyChangeListener() { //$NON-NLS-1$ public void propertyChange(PropertyChangeEvent e) { refreshGUI(); } }); } /** * Draws the frame into a graphics object suitable for printing. * @param g * @param pageFormat * @param pageIndex * @return status code * @exception PrinterException */ public int printToGraphics(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException { if(pageIndex>=1) { // only one page available return Printable.NO_SUCH_PAGE; } if(g==null) { return Printable.NO_SUCH_PAGE; } Graphics2D g2 = (Graphics2D) g; double scalex = pageFormat.getImageableWidth()/mainFrame.getWidth(); double scaley = pageFormat.getImageableHeight()/mainFrame.getHeight(); double scale = Math.min(scalex, scaley); g2.translate((int) pageFormat.getImageableX(), (int) pageFormat.getImageableY()); g2.scale(scale, scale); //frame.paintAll(g2); mainFrame.paint(g); return Printable.PAGE_EXISTS; } protected void refreshGUI() { createMenuBar(); mainFrame.pack(); } /** * Adds a PropertyChangeListener. * * @param listener the object requesting property change notification */ public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Removes a PropertyChangeListener. * * @param listener the listener requesting removal */ public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } /** * Prints a string in the control's message area followed by a CR and LF. * GUI controls will usually display messages in a non-editable text area. * * @param s */ public void println(String s) { print(s+"\n"); //$NON-NLS-1$ } /** * Prints a blank line in the control's message area. GUI controls will usually display * messages in a non-editable text area. */ public void println() { print("\n"); //$NON-NLS-1$ } /** * Prints a string in the control's message area. * GUI controls will usually display messages in a non-editable text area. * * @param s */ public void print(final String s) { if(s==null) { return; // nothing to print } messageFrame.setVisible(true); if(SwingUtilities.isEventDispatchThread()||Thread.currentThread().getName().equals("main")) { //$NON-NLS-1$ messageArea.append(s); return; } Runnable doLater = new Runnable() { public void run() { messageArea.append(s); } }; // Update from the event queue. java.awt.EventQueue.invokeLater(doLater); } /** * Remove all text from the message area. */ public void clearMessages() { if(SwingUtilities.isEventDispatchThread()||Thread.currentThread().getName().equals("main")) { //$NON-NLS-1$ messageArea.setText(""); //$NON-NLS-1$ return; } Runnable doLater = new Runnable() { public void run() { messageArea.setText(""); //$NON-NLS-1$ } }; // Update from the event queue. java.awt.EventQueue.invokeLater(doLater); } // private void appendMessageX(final String str) { // Runnable doRun = new Runnable() { // public void run() { // messageArea.append(str); // } // }; // if(SwingUtilities.isEventDispatchThread()) { // doRun.run(); // }else{ // SwingUtilities.invokeLater(doRun); // } // } // /** * Stops the animation and prints a message. * @param message String */ public void calculationDone(String message) { if((message==null)||message.trim().equals("")) { //$NON-NLS-1$ return; } super.calculationDone(message); } /** * Renders the frame. Subclass this method to render the contents of this frame in the calling thread. */ public void render() {} /** * Adds an existing object to this control. * @param object Object * @param classname String * @param propList String * @return ControlElement */ public ControlElement addObject(Object object, String classname, String propList) { if(object instanceof DrawingPanel) { defaultDrawingPanel = (DrawingPanel) object; if(snapshotItem!=null) { snapshotItem.setEnabled(true); } if(videoItem!=null) { videoItem.setEnabled(true); } } return super.addObject(object, classname, propList); } /** * Clears data from drawing objects within this frame. * * Override this method to clear objects that have data. */ public void clearData() { if(defaultDrawingPanel!=null) { ArrayList<?> list = defaultDrawingPanel.getDrawables(Dataset.class); Iterator<?> it = list.iterator(); while(it.hasNext()) { // copy only the objects of the correct type Dataset obj = (Dataset) it.next(); obj.clear(); } list = defaultDrawingPanel.getDrawables(DatasetManager.class); it = list.iterator(); while(it.hasNext()) { // copy only the objects of the correct type DatasetManager obj = (DatasetManager) it.next(); obj.clear(); } defaultDrawingPanel.invalidateImage(); } } /** * Clears data from drawing objects within this frame. * * Override this method to clear and repaint objects that have data. */ public void clearDataAndRepaint() { clearData(); if(defaultDrawingPanel!=null) { defaultDrawingPanel.repaint(); } } /** * Gets the frame that contains the control. * * @return */ public Container getTopLevelAncestor() { return mainFrame; } /** * Gets the frame's root pane. Implementation of RootPaneContainer. * * @return */ public JRootPane getRootPane() { return mainFrame.getRootPane(); } /** * Gets the frame's content pane. Implementation of RootPaneContainer. * * @return content pane of the frame */ public Container getContentPane() { return mainFrame.getContentPane(); } /** * Sets the frame's content pane. Implementation of RootPaneContainer. * @param contentPane */ public void setContentPane(Container contentPane) { mainFrame.setContentPane(contentPane); } /** * Implementation of RootPaneContainer. * * @see javax.swing.RootPaneContainer * * @return layeredPane of the frame */ public JLayeredPane getLayeredPane() { return mainFrame.getLayeredPane(); } /** * Implementation of RootPaneContainer. * * @see javax.swing.RootPaneContainer * @param layeredPane */ public void setLayeredPane(JLayeredPane layeredPane) { mainFrame.setLayeredPane(layeredPane); } /** * Implementation of RootPaneContainer. * * @see javax.swing.RootPaneContainer * * @return glass pane component */ public Component getGlassPane() { return mainFrame.getGlassPane(); } /** * Implementation of RootPaneContainer. * * @see javax.swing.RootPaneContainer * @param glassPane */ public void setGlassPane(Component glassPane) { mainFrame.setGlassPane(glassPane); } /* * Creates a menu in the menu bar from the given XML document. * @param xmlMenu name of the xml file with menu data */ public void parseXMLMenu(String xmlMenu) { System.out.println("The parseXMLMenu method has been disabled to reduce the size OSP jar files."); //$NON-NLS-1$ //parseXMLMenu(xmlMenu, null); } /* * public void parseXMLMenu(String xmlMenu) { * if(menuBar==null) { * return; * } * XMLControl xml = new XMLControlElement(xmlMenu); * if(xml.failedToRead()) { * OSPLog.info("Tools menu not found: "+xmlMenu); //$NON-NLS-1$ * } else { * Class type = xml.getObjectClass(); * if((type!=null)&&org.opensourcephysics.tools.LaunchNode.class.isAssignableFrom(type)) { * // load the xml data into a launch node and add the menu item * org.opensourcephysics.tools.LaunchNode node = (org.opensourcephysics.tools.LaunchNode) xml.loadObject(null); * // get the menu name and find or create the menu * String menuName = node.toString(); * JMenu menu = null; * for(int i = 0; i<menuBar.getMenuCount(); i++) { * JMenu next = menuBar.getMenu(i); * if(next.getText().equals(menuName)) { * menu = next; * break; * } * } * if(menu==null) { * menu = new JMenu(menuName); * menuBar.add(menu); * menuBar.validate(); * } * // add the node item to the menu * node.setLaunchObject(model); * node.addMenuItemsTo(menu); * OSPLog.finest("Tools menu loaded: "+xmlMenu); //$NON-NLS-1$ * } * } * } */ // The following methods the an XML framework for OSPApplications. protected OSPApplication app; public void saveXML() { JFileChooser chooser = OSPRuntime.getChooser(); int result = chooser.showSaveDialog(null); if(result==JFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); // check to see if file already exists if(file.exists()) { int selected = JOptionPane.showConfirmDialog(null, EjsRes.getString("EjsControlFrame.ReplaceExisting_dialog")+file.getName() //$NON-NLS-1$ +EjsRes.getString("EjsControlFrame.question_mark"), EjsRes.getString( //$NON-NLS-1$ "EjsControlFrame.RepalceFile_dialog_message"), //$NON-NLS-1$ JOptionPane.YES_NO_CANCEL_OPTION); if(selected!=JOptionPane.YES_OPTION) { return; } } OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString(); 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$ } XMLControl xml = new XMLControlElement(getOSPApp()); xml.write(fileName); } } /** * Gets the OSP Application controlled by this frame. */ public OSPApplication getOSPApp() { if(app==null) { app = new OSPApplication(this, model); } return app; } /** * Loads the current XML default. */ public void loadDefaultXML() { if(xmlDefault!=null) { xmlDefault.loadObject(getOSPApp()); clearItem.setEnabled(true); } } /** * Clears the current XML default. */ public void clearDefaultXML() { if((xmlDefault==null)||(model==null)) { return; } xmlDefault = null; clearItem.setEnabled(false); if(model instanceof Calculation) { ((Calculation) model).resetCalculation(); ((Calculation) model).calculate(); } else if(model instanceof Animation) { ((Animation) model).stopAnimation(); ((Animation) model).resetAnimation(); ((Animation) model).initializeAnimation(); } GUIUtils.repaintOSPFrames(); } public void loadXML(String fileName) { if((fileName==null)||fileName.trim().equals("")) { //$NON-NLS-1$ loadXML(); return; } XMLControlElement xml = null; try { xml = new XMLControlElement(fileName); } catch(Exception ex) { System.out.println("XML file not loaded: "+fileName); //$NON-NLS-1$ System.out.println("EjsControlFrame Exception: "+ex); //$NON-NLS-1$ //ex.printStackTrace(); return; } loadXML(xml, false); } public void loadXML(XMLControlElement xml, boolean compatibleModel) { if(xml==null) { OSPLog.finer("XML not found in EjsControlFrame loadXML method."); //$NON-NLS-1$ return; } // load xml into app if xml object class is an OSPApplication if(OSPApplication.class.isAssignableFrom(xml.getObjectClass())) { XMLControlElement mControl = (XMLControlElement) xml.getChildControl("model"); //$NON-NLS-1$ if(mControl==null) { // control class cannot be found JOptionPane.showMessageDialog(mainFrame, "XML Control not found.", //$NON-NLS-1$ "Data not loaded.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$ return; } Class<?> modelClass = mControl.getObjectClass(); if(modelClass==null) { // model class cannot be found in classpath JOptionPane.showMessageDialog(mainFrame, "Model specified in file not found.", //$NON-NLS-1$ "Data not loaded.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$ return; } //System.out.println("model in xml " +modelClass); //System.out.println("this model " +model.getClass()); boolean loaderMatch = XML.getLoader(modelClass).getClass()==XML.getLoader(model.getClass()).getClass(); compatibleModel = compatibleModel||(modelClass==model.getClass())|| // identical model classes are always compatible (modelClass.isAssignableFrom(model.getClass())&&loaderMatch); // subclasses with identical loaders are assumed to be compatible //System.out.println("xml model Assignable to this model " +modelClass.isAssignableFrom(model.getClass())); //System.out.println("this model Assignable to xml model " +model.getClass().isAssignableFrom(modelClass)); if(!compatibleModel) { JOptionPane.showMessageDialog(mainFrame, "Data not loaded. Data was created by: "+modelClass+".", //$NON-NLS-1$ //$NON-NLS-2$ "Incompatible data file.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$ return; } app = getOSPApp(); app.setCompatibleModel(compatibleModel); xml.loadObject(getOSPApp()); app.setCompatibleModel(false); if(model.getClass()==app.getLoadedModelClass()) { // classes match so we have a new default xmlDefault = xml; clearItem.setEnabled(true); } else if(app.getLoadedModelClass()!=null) { // a model was imported; create xml from current model xmlDefault = new XMLControlElement(getOSPApp()); clearItem.setEnabled(true); } else { // models are not compatible xmlDefault = null; clearItem.setEnabled(false); } } else { JOptionPane.showMessageDialog(mainFrame, "Data for: "+xml.getObjectClass()+".", //$NON-NLS-1$ //$NON-NLS-2$ "OSP Application data not found.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$ } } public void loadXML() { JFileChooser chooser = OSPRuntime.getChooser(); int result = chooser.showOpenDialog(null); if(result==JFileChooser.APPROVE_OPTION) { String fileName = chooser.getSelectedFile().getAbsolutePath(); loadXML(XML.getRelativePath(fileName)); } } public void inspectXML() { // display a TreePanel in a modal dialog XMLControl xml = new XMLControlElement(getOSPApp()); 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 loadXML(String[] args) { if(args!=null) { for(int i = 0; i<args.length; i++) { loadXML(args[i]); } } } class EjsFrame extends OSPFrame implements MainFrame { public OSPFrame getMainFrame() { return this; } public void render() { EjsControlFrame.this.render(); } public void clearData() { EjsControlFrame.this.clearData(); } public void clearDataAndRepaint() { EjsControlFrame.this.clearDataAndRepaint(); } public void dispose() { messageFrame.setVisible(false); messageFrame.dispose(); super.dispose(); } /** * Invalidates image buffers if a drawing panel is buffered. */ public void invalidateImage() { if(defaultDrawingPanel!=null) { defaultDrawingPanel.invalidateImage(); } } public OSPApplication getOSPApp() { return EjsControlFrame.this.getOSPApp(); } } } /* * 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 */