/* * 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.tools; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JToolBar; import javax.swing.ListCellRenderer; import javax.swing.MenuElement; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import org.opensourcephysics.controls.OSPLog; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.display.ResizableIcon; import org.opensourcephysics.display.TextFrame; /** * This tool allows users to create and manage editable Functions. * * @author Douglas Brown */ @SuppressWarnings("serial") public class FunctionTool extends JDialog implements PropertyChangeListener { // static fields protected static String[] parserNames = new String[] { "e", "pi", "min", "mod", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "sin", "cos", "abs", "log", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "acos", "acosh", "ceil", "cosh", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "asin", "asinh", "atan", "atanh", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "exp", "frac", "floor", "int", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "random", "round", "sign", "sinh", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "step", "tanh", "atan2", "max", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "sqrt", "sqr", "if", "tan"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$; protected static String[] parserOperators = new String[] { "!", ",", ".", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "+", "-", "*", "/", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "^", "=", ">", "<", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "&", "|", "(", ")"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$; // instance fields protected Set<DatasetCurveFitter> curveFitters = new HashSet<DatasetCurveFitter>(); protected Map<String, FunctionPanel> panels = new TreeMap<String, FunctionPanel>(); // maps name to FunctionPanel protected HashSet<String> forbiddenNames = new HashSet<String>(); protected JPanel contentPane = new JPanel(new BorderLayout()); protected JPanel noData; protected JToolBar toolbar, dropdownbar; protected JLabel dropdownLabel; protected JComboBox dropdown; protected JPanel north = new JPanel(new BorderLayout()); protected FunctionPanel selectedPanel; protected JScrollPane selectedPanelScroller; protected JButton helpButton, closeButton, fontButton, undoButton, redoButton; protected JPopupMenu popup; protected JMenuItem defaultFontSizeItem; protected JPanel buttonbar = new JPanel(new FlowLayout()); protected Component[] toolbarComponents; // may be null protected String helpPath = ""; //$NON-NLS-1$ protected String helpBase = "http://www.opensourcephysics.org/online_help/tools/"; //$NON-NLS-1$ protected TextFrame helpFrame; protected JDialog helpDialog; protected ActionListener helpAction; protected int fontLevel = 0; protected boolean refreshing; /** * Constructs a tool for the specified component (may be null) * * @param comp Component used to get Frame owner of this Dialog */ public FunctionTool(Component comp) { this(comp, null); } /** * Constructs a tool with custom buttons or other components. * * @param comp Component used to get Frame owner of this Dialog * @param toolbarItems an array of custom buttons or other components */ public FunctionTool(Component comp, Component[] toolbarItems) { // modal if no owner (ie if comp is null) super(JOptionPane.getFrameForComponent(comp), comp==null); addForbiddenNames(parserNames); addForbiddenNames(UserFunction.dummyVars); setName("FunctionTool"); //$NON-NLS-1$ createGUI(); setToolbarComponents(toolbarItems); } /** * Sets the custom buttons or other components. * * @param toolbarItems an array of components (may be null) */ public void setToolbarComponents(Component[] toolbarItems) { toolbarComponents = toolbarItems; refreshGUI(); } /** * Gets the custom buttons or other components. * * @return an array of components (may be null) */ public Component[] getToolbarComponents() { return toolbarComponents; } /** * Adds a FunctionPanel. * * @param name a descriptive name * @param panel the FunctionPanel * @return the added panel */ public FunctionPanel addPanel(String name, FunctionPanel panel) { OSPLog.finest("adding panel "+name); //$NON-NLS-1$ panel.setFontLevel(fontLevel); panel.setName(name); panel.setFunctionTool(this); panels.put(name, panel); panel.addForbiddenNames(forbiddenNames.toArray(new String[0])); refreshDropdown(name); panel.clearSelection(); return panel; } /** * Removes a named FunctionPanel. * * @param name the name * @return the removed panel, if any */ public FunctionPanel removePanel(String name) { FunctionPanel panel = panels.get(name); if(panel!=null) { OSPLog.finest("removing panel "+name); //$NON-NLS-1$ panels.remove(name); panel.dispose(); refreshDropdown(null); firePropertyChange("panel", panel, null); //$NON-NLS-1$ } return panel; } /** * Renames a FunctionPanel. * * @param prevName the previous name * @param newName the new name * @return the renamed panel */ public FunctionPanel renamePanel(String prevName, String newName) { FunctionPanel panel = getPanel(prevName); if((panel==null)||prevName.equals(newName)) { return panel; } OSPLog.finest("renaming panel "+prevName+" to "+newName); //$NON-NLS-1$ //$NON-NLS-2$ panels.remove(prevName); panels.put(newName, panel); panel.prevName = prevName; panel.setName(newName); refreshDropdown(newName); return panel; } /** * Selects a FunctionPanel by name. * * @param name the name */ public void setSelectedPanel(String name) { Object item = getDropdownItem(name); if (item != null) dropdown.setSelectedItem(item); } /** * Returns the name of the selected FunctionPanel. * * @return the name */ public String getSelectedName() { if(selectedPanel==null) { return null; } Iterator<String> it = panels.keySet().iterator(); while(it.hasNext()) { String name = it.next(); if(panels.get(name)==selectedPanel) { return name; } } return null; } /** * Returns the selected FunctionPanel. * * @return the FunctionPanel */ public FunctionPanel getSelectedPanel() { return getPanel(getSelectedName()); } /** * Returns the named FunctionPanel. * * @param name the name * @return the FunctionPanel */ public FunctionPanel getPanel(String name) { return(name==null) ? null : panels.get(name); } /** * Returns the set of all panel names. * * @return a set of names */ public Set<String> getPanelNames() { return panels.keySet(); } /** * Clears all FunctionPanels. */ public void clearPanels() { OSPLog.finest("clearing panels"); //$NON-NLS-1$ panels.clear(); refreshDropdown(null); } /** * Responds to property change events from TrackerPanel. * * @param e the property change event */ public void propertyChange(PropertyChangeEvent e) { refreshGUI(); if (FunctionTool.this instanceof FitBuilder) { // refresh dropdown since localized names change refreshDropdown(null); } } /** * Adds names to the forbidden set. * * @param names the names to add */ public void addForbiddenNames(String[] names) { for(int i = 0; i<names.length; i++) { forbiddenNames.add(names[i]); } } /** * Overrides JDialog setVisible method. * * @param vis true to show this tool */ public void setVisible(boolean vis) { if (contentPane.getTopLevelAncestor()==this) super.setVisible(vis); else contentPane.getTopLevelAncestor().setVisible(vis); firePropertyChange("visible", null, new Boolean(vis)); //$NON-NLS-1$ } /** * Overrides JDialog isVisible method. * * @return true if visible */ public boolean isVisible() { if (contentPane.getTopLevelAncestor()==this) return super.isVisible(); return contentPane.getTopLevelAncestor().isVisible(); } /** * Sets the path of the help file. * * @param path a filename or url */ public void setHelpPath(String path) { helpPath = path; } /** * Sets the help action. this will replace the current help action * * @param action a custom help action */ public void setHelpAction(ActionListener action) { helpButton.removeActionListener(helpAction); helpAction = action; helpButton.addActionListener(helpAction); } /** * Reports if this is empty. * * @return true if empty */ public boolean isEmpty() { return panels.isEmpty(); } /** * Sets the font level. * * @param level the level */ public void setFontLevel(int level) { level = Math.max(0, level); if(level==fontLevel) { return; } fontLevel = level; boolean vis = isVisible(); setVisible(false); FontSizer.setFonts(this, level); FontSizer.setFonts(contentPane, level); FontSizer.setFonts(popup, level); FontSizer.setFonts(fontButton, level); for(Iterator<FunctionPanel> it = panels.values().iterator(); it.hasNext(); ) { FunctionPanel next = it.next(); if(next==getSelectedPanel()) { continue; } next.setFontLevel(level); } if(level<popup.getSubElements().length) { MenuElement[] e = popup.getSubElements(); JRadioButtonMenuItem item = (JRadioButtonMenuItem) e[level]; item.setSelected(true); } int n = dropdown.getSelectedIndex(); Object[] items = new Object[dropdown.getItemCount()]; for (int i=0; i<items.length; i++) { items[i] = dropdown.getItemAt(i); } DefaultComboBoxModel model = new DefaultComboBoxModel(items); dropdown.setModel(model); dropdown.setSelectedItem(n); java.awt.Container c = contentPane.getTopLevelAncestor(); Dimension dim = c.getSize(); dim.width = c.getMinimumSize().width; int h = (int)(280*FontSizer.getFactor(level)); h = Math.max(h, dim.height); h = Math.min(h, (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()); dim.height = h; setSize(dim); c.setSize(dim); setVisible(vis); refreshDropdown(null); } /** * Gets the font level. * * @return the level */ public int getFontLevel() { return fontLevel; } /** * Sets the independent variables of all function panels. * * @param vars the independent variable names */ public void setDefaultVariables(String[] vars) { for(String name : getPanelNames()) { FunctionPanel panel = getPanel(name); UserFunctionEditor editor = (UserFunctionEditor) panel.getFunctionEditor(); editor.setDefaultVariables(vars); editor.repaint(); } } /** * Fires a property change. This makes this method visible to the tools package. */ protected void firePropertyChange(String name, Object oldObj, Object newObj) { super.firePropertyChange(name, oldObj, newObj); } /** * Creates the GUI. */ private void createGUI() { // listen to ToolsRes for locale changes ToolsRes.addPropertyChangeListener("locale", this); //$NON-NLS-1$ // configure the dialog setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); // create the noData panel noData = new JPanel(new BorderLayout()); // create the toolbars dropdownbar = new JToolBar(); dropdownbar.setFloatable(false); dropdownLabel = new JLabel(); dropdownLabel.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 2)); dropdownLabel.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { String name = getSelectedName(); if(name!=null) { FunctionPanel panel = panels.get(name); panel.clearSelection(); } } }); dropdownbar.add(dropdownLabel); // create dropdown dropdown = new JComboBox() { // override getMaximumSize method so has same height as buttons public Dimension getMaximumSize() { Dimension dim = super.getMaximumSize(); if (toolbarComponents != null && toolbarComponents.length > 0 & toolbarComponents[0] instanceof JButton) { JButton button = (JButton)toolbarComponents[0]; dim.height = button.getHeight(); } return dim; } // override addItem method to alphabetize added items public void addItem(Object obj) { if (obj==null) return; int count = getItemCount(); for (int i=0; i<count; i++) { if (obj.equals(getItemAt(i))) return; } // add in alphabetical order, ignoring case Object[] array = (Object[])obj; String name = array.length>2? (String)array[2]: (String)array[1]; // substitute localized name if this tool is a FitBuilder if (FunctionTool.this instanceof FitBuilder) { name = FitBuilder.localize(name); } boolean added = false; for (int i=0; i<count; i++) { Object[] nextArray = (Object[])getItemAt(i); String next = nextArray.length>2? (String)nextArray[2]: (String)nextArray[1]; // substitute localized name if this tool is a FitBuilder if (FunctionTool.this instanceof FitBuilder) { next = FitBuilder.localize(next); } if (name.compareToIgnoreCase(next)<0) { // next comes after name, so insert object here insertItemAt(obj, i); added = true; break; } } if (!added) { // add at end super.addItem(obj); } } }; dropdown.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0)); dropdownbar.add(dropdown); // custom cell renderer for dropdown items DropdownRenderer renderer= new DropdownRenderer(); dropdown.setRenderer(renderer); dropdown.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Object item = dropdown.getSelectedItem(); if(item!=null) { String name = ((Object[])item)[1].toString(); select(name); FunctionPanel panel = panels.get(name); if(panel!=null) { panel.getFunctionTable().clearSelection(); panel.getFunctionTable().selectOnFocus = false; panel.getParamTable().clearSelection(); panel.getParamTable().selectOnFocus = false; panel.refreshGUI(); } } helpButton.requestFocusInWindow(); } }); // create toolbar for custom components toolbar = new JToolBar(); toolbar.setFloatable(false); north.add(dropdownbar, BorderLayout.SOUTH); north.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); // create buttons closeButton = new JButton(ToolsRes.getString("Tool.Button.Close")); //$NON-NLS-1$ closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setVisible(false); } }); helpAction = new ActionListener() { public void actionPerformed(ActionEvent e) { if(helpFrame==null) { // show web help if available String help = XML.getResolvedPath(helpPath, helpBase); if(ResourceLoader.getResource(help)!=null) { helpFrame = new TextFrame(help); } else { String classBase = "/org/opensourcephysics/resources/tools/html/"; //$NON-NLS-1$ help = XML.getResolvedPath(helpPath, classBase); helpFrame = new TextFrame(help); } // create help dialog helpDialog = new JDialog(FunctionTool.this, false); helpDialog.setContentPane(helpFrame.getContentPane()); helpDialog.setSize(700, 550); // center on the screen Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); int x = (dim.width-helpDialog.getBounds().width)/2; int y = (dim.height-helpDialog.getBounds().height)/2; helpDialog.setLocation(x, y); } helpDialog.setVisible(true); } }; helpButton = new JButton(ToolsRes.getString("Tool.Button.Help")); //$NON-NLS-1$ helpButton.addActionListener(helpAction); undoButton = new JButton(ToolsRes.getString("DataFunctionPanel.Button.Undo")); //$NON-NLS-1$ redoButton = new JButton(ToolsRes.getString("DataFunctionPanel.Button.Redo")); //$NON-NLS-1$ // create font sizer button and popup fontButton = new JButton(ToolsRes.getString("Tool.Menu.FontSize")); //$NON-NLS-1$ popup = new JPopupMenu(); ButtonGroup group = new ButtonGroup(); Action fontSizeAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { int i = Integer.parseInt(e.getActionCommand()); setFontLevel(i); } }; for(int i = 0; i<4; i++) { JMenuItem item = new JRadioButtonMenuItem("+"+i); //$NON-NLS-1$ if(i==0) { defaultFontSizeItem = item; } item.addActionListener(fontSizeAction); item.setActionCommand(""+i); //$NON-NLS-1$ popup.add(item); group.add(item); if(i==fontLevel) { item.setSelected(true); } } fontButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { popup.show(fontButton, 0, fontButton.getHeight()); } }); // prepare button bar buttonbar.setBorder(BorderFactory.createEtchedBorder()); buttonbar.add(helpButton); buttonbar.add(undoButton); buttonbar.add(redoButton); buttonbar.add(fontButton); buttonbar.add(closeButton); contentPane.add(north, BorderLayout.NORTH); contentPane.add(noData, BorderLayout.CENTER); contentPane.add(buttonbar, BorderLayout.SOUTH); setContentPane(contentPane); pack(); Dimension dim = getSize(); dim.height = Math.max(360, dim.height); setSize(dim); buttonbar.remove(undoButton); buttonbar.remove(redoButton); buttonbar.remove(fontButton); dropdown.setEnabled(false); dropdownLabel.setEnabled(false); // center this on the screen dim = Toolkit.getDefaultToolkit().getScreenSize(); int x = (dim.width-getBounds().width)/2; int y = (dim.height-getBounds().height)/2; setLocation(x, y); } /** * Refreshes the GUI. */ protected void refreshGUI() { // refresh toolbar if(toolbarComponents==null) { north.remove(toolbar); } else { north.add(toolbar, BorderLayout.NORTH); toolbar.removeAll(); for(int i = 0; i<toolbarComponents.length; i++) { toolbar.add(toolbarComponents[i]); } } if(selectedPanel!=null) { String label = selectedPanel.getLabel(); dropdownLabel.setText(label+":"); //$NON-NLS-1$ } closeButton.setText(ToolsRes.getString("Tool.Button.Close")); //$NON-NLS-1$ closeButton.setToolTipText(ToolsRes.getString("Tool.Button.Close.ToolTip")); //$NON-NLS-1$ helpButton.setText(ToolsRes.getString("Tool.Button.Help")); //$NON-NLS-1$ helpButton.setToolTipText(ToolsRes.getString("Tool.Button.Help.ToolTip")); //$NON-NLS-1$ fontButton.setText(ToolsRes.getString("Tool.Menu.FontSize")); //$NON-NLS-1$ fontButton.setToolTipText(ToolsRes.getString("FunctionTool.Button.Display.Tooltip")); //$NON-NLS-1$ defaultFontSizeItem.setText(ToolsRes.getString("Tool.MenuItem.DefaultFontSize")); //$NON-NLS-1$ Iterator<FunctionPanel> it = panels.values().iterator(); while(it.hasNext()) { FunctionPanel panel = it.next(); panel.refreshGUI(); } Dimension dim = getSize(); dim.width = Math.max(dim.width, getMinimumSize().width); setSize(dim); helpButton.requestFocusInWindow(); } /** * Gets the dropdown item, if any, with the specified name. * * @param name the name * @return the dropdown item */ private Object getDropdownItem(String name) { for (int i = 0; i < dropdown.getItemCount(); i++) { Object item = dropdown.getItemAt(i); String itemName = ((Object[])item)[1].toString(); if (itemName.equals(name)) return item; } return null; } /** * Refreshes the dropdown and selects a specified panel. * If name is null, the current selection is retained if possible. * * @param name the name of the panel to select */ public void refreshDropdown(String name) { refreshing = true; // prevents selecting items while adding to dropdown if(name==null) { Object item = dropdown.getSelectedItem(); if (item != null) name = ((Object[])item)[1].toString(); } Object[] toSelect = null; dropdown.removeAllItems(); for (String next: panels.keySet()) { FunctionPanel panel = panels.get(next); String displayName = panel.getDisplayName(); Icon icon = panel.getIcon(); if (icon!=null && icon instanceof ResizableIcon) { int factor = FontSizer.getIntegerFactor(FontSizer.getLevel()); ((ResizableIcon)icon).resize(factor); } Object item = new Object[] {icon, next, displayName}; dropdown.addItem(item); if (toSelect==null || next.equals(name)) { toSelect = (Object[])item; } } refreshing = false; // select desired item if (toSelect != null) { dropdown.setSelectedItem(toSelect); } else select(null); Runnable runner = new Runnable() { public void run() { dropdown.revalidate(); helpButton.requestFocusInWindow(); } }; SwingUtilities.invokeLater(runner); } /** * Selects the named function panel. * * @param name the name */ private void select(String name) { if (refreshing) return; FunctionPanel panel = (name==null) ? null : panels.get(name); FunctionPanel prev = selectedPanel; if(selectedPanel!=null) { contentPane.remove(selectedPanelScroller); } else { contentPane.remove(noData); } selectedPanel = panel; dropdown.setEnabled(panel!=null); dropdownLabel.setEnabled(panel!=null); if(panel!=null) { selectedPanelScroller = new JScrollPane(panel); contentPane.add(selectedPanelScroller, BorderLayout.CENTER); panel.refreshGUI(); } else { contentPane.add(noData, BorderLayout.CENTER); buttonbar.removeAll(); buttonbar.add(helpButton); buttonbar.add(closeButton); } java.awt.Container c = contentPane.getTopLevelAncestor(); c.validate(); refreshGUI(); c.repaint(); firePropertyChange("panel", prev, panel); //$NON-NLS-1$ } /** * Gets a unique name. * * @param proposedName the proposed name * @return the unique name */ protected String getUniqueName(String proposedName) { // construct a unique name from that proposed by adding trailing digit int i = 0; String name = proposedName; // special case for new fits defined by DatasetCurveFitter.fitBuilder if(ToolsRes.getString("DatasetCurveFitter.NewFit.Name").equals(proposedName)) { //$NON-NLS-1$ i++; name = name+i; } while(panels.keySet().contains(name)||forbiddenNames.contains(name)) { i++; name = proposedName+i; } return name; } /** * Custom renderer to show name and icon in dropdown list items */ public class DropdownRenderer extends JLabel implements ListCellRenderer { public DropdownRenderer() { setOpaque(true); setHorizontalAlignment(LEFT); setVerticalAlignment(CENTER); setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0)); } public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } if (value != null) { Object[] array = (Object[])value; setIcon((Icon)array[0]); String val = array.length>2? (String)array[2]: (String)array[1]; // substitute localized name if this tool is a FitBuilder if (FunctionTool.this instanceof FitBuilder) { val = FitBuilder.localize(val); } setText(val); } else { setIcon(null); setText(null); } return this; } } //__________________________ static methods ___________________________ /** * Returns an ObjectLoader to save and load data for this class. * * @return the object loader */ public static XML.ObjectLoader getLoader() { return new Loader(); } /** * A class to save and load data for this class. */ static class Loader implements XML.ObjectLoader { public void saveObject(XMLControl control, Object obj) { FunctionTool tool = (FunctionTool)obj; ArrayList<FunctionPanel> functions = new ArrayList<FunctionPanel>(tool.panels.values()); control.setValue("functions", functions); //$NON-NLS-1$ } public Object createObject(XMLControl control) { return null; } public Object loadObject(XMLControl control, Object obj) { FunctionTool tool = (FunctionTool)obj; ArrayList<?> functions = (ArrayList<?>) control.getObject("functions"); //$NON-NLS-1$ if(functions!=null) { for(Iterator<?> it = functions.iterator(); it.hasNext(); ) { FunctionPanel panel = (FunctionPanel) it.next(); tool.addPanel(panel.getName(), panel); } } 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 */