package org.opensourcephysics.tools; import java.awt.Component; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; import javax.swing.Box; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JToolBar; import javax.swing.filechooser.FileFilter; import org.opensourcephysics.controls.ListChooser; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.controls.XMLControlElement; import org.opensourcephysics.controls.XMLProperty; import org.opensourcephysics.display.Dataset; import org.opensourcephysics.display.OSPRuntime; import org.opensourcephysics.display.TeXParser; /** * This is a FunctionTool used by DatasetCurveFitter to build, save and load custom fit functions. * Some methods are tailored for use with DataTool since that is its main application. * * @author Doug Brown * */ public class FitBuilder extends FunctionTool { static JFileChooser chooser; static java.io.FileFilter xmlFilter; static String[] preferredAutoloadSearchPaths; static Collection<String> initialAutoloadSearchPaths = new TreeSet<String>(); static Map<String, String[]> autoloadMap = new TreeMap<String, String[]>(); static { xmlFilter = new java.io.FileFilter() { // accept only *.xml files. public boolean accept(File f) { if(f==null || f.isDirectory()) return false; String ext = XML.getExtension(f.getName()); if (ext!=null && "xml".equals(ext.toLowerCase())) return true; //$NON-NLS-1$ return false; } }; // load preferred autoload search paths and excluded functions from OSPRuntime.preferences preferredAutoloadSearchPaths = (String[])OSPRuntime.getPreference("autoload_search_paths"); //$NON-NLS-1$ String[][] autoloadData = (String[][])OSPRuntime.getPreference("autoload_exclusions"); //$NON-NLS-1$ if (autoloadData!=null) { for (String[] next: autoloadData) { String filePath = XML.forwardSlash(next[0]); String[] functions = new String[next.length-1]; System.arraycopy(next, 1, functions, 0, functions.length); autoloadMap.put(filePath, functions); } } } protected JButton newFitButton, deleteFitButton, cloneFitButton, loadButton, saveButton, autoloadButton; protected Component parent; protected TreeSet<String> addedFits = new TreeSet<String>(); protected String defaultFitName; protected AutoloadManager autoloadManager; /** * Constructor * * @param c a component to determine the dialog owner */ public FitBuilder(Component c) { super(c); parent = c; newFitButton = new JButton(ToolsRes.getString("DatasetCurveFitter.Button.NewFit.Text")); //$NON-NLS-1$ newFitButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.Button.NewFit.Tooltip")); //$NON-NLS-1$ newFitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // create new user function and function panel String name = getUniqueName(ToolsRes.getString("DatasetCurveFitter.NewFit.Name")); //$NON-NLS-1$ UserFunction f = new UserFunction(name); Dataset dataset = null; DatasetCurveFitter fitter = getSelectedCurveFitter(); if (fitter!=null) { dataset = fitter.getData(); } String var = (dataset==null)? "x": //$NON-NLS-1$ TeXParser.removeSubscripting(dataset.getColumnName(0)); f.setExpression("0", new String[] {var}); //$NON-NLS-1$ addFitFunctionPanel(f); } }); deleteFitButton = new JButton(ToolsRes.getString("DatasetCurveFitter.Button.DeleteFit.Text")); //$NON-NLS-1$ deleteFitButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.Button.DeleteFit.Tooltip")); //$NON-NLS-1$ deleteFitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // remove selected fit and panel String name = getSelectedName(); removePanel(name); } }); cloneFitButton = new JButton(ToolsRes.getString("DatasetCurveFitter.Button.Clone.Text")); //$NON-NLS-1$ cloneFitButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.Button.Clone.Tooltip")); //$NON-NLS-1$ cloneFitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final Map<String, KnownFunction> fits = new HashMap<String, KnownFunction>(); final ArrayList<String> fitnames = new ArrayList<String>(); for (DatasetCurveFitter fitter: curveFitters) { for (int i = 0; i < fitter.fitDropDown.getItemCount(); i++) { String name = fitter.fitDropDown.getItemAt(i).toString(); if (!fitnames.contains(name)) { fitnames.add(name); fits.put(name, fitter.fitMap.get(name)); } } } // inner popup menu listener class ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { for (String name: fitnames) { if (name.equals(e.getActionCommand())) { DatasetCurveFitter fitter = getSelectedCurveFitter(); if (fitter!=null) { KnownFunction f = fits.get(name); UserFunction uf = fitter.createClone(f, name); UserFunctionEditor editor = new UserFunctionEditor(); editor.setMainFunctions(new UserFunction[] {uf}); FitFunctionPanel panel = new FitFunctionPanel(editor); addPanel(uf.getName(), panel); } } } } }; // create popup menu and add existing fit function items JPopupMenu popup = new JPopupMenu(); for (String name: fitnames) { JMenuItem item = new JMenuItem(name); item.setActionCommand(name); item.addActionListener(listener); popup.add(item); } // show the popup below the button popup.show(cloneFitButton, 0, cloneFitButton.getHeight()); } }); String imageFile = "/org/opensourcephysics/resources/tools/images/open.gif"; //$NON-NLS-1$ Icon openIcon = ResourceLoader.getIcon(imageFile); loadButton = new JButton(openIcon); loadButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadFits(); } }); imageFile = "/org/opensourcephysics/resources/tools/images/save.gif"; //$NON-NLS-1$ Icon saveIcon = ResourceLoader.getIcon(imageFile); saveButton = new JButton(saveIcon); saveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { saveFits(); } }); // create autoloadButton autoloadButton = new JButton(); autoloadButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { AutoloadManager manager = getAutoloadManager(); manager.refreshAutoloadData(); manager.setVisible(true); } }); setToolbarComponents(new Component[] {loadButton, saveButton, new JToolBar.Separator(), newFitButton, cloneFitButton, deleteFitButton, Box.createHorizontalGlue(), autoloadButton}); // autoload fits for (String dir: getInitialSearchPaths()) { autoloadFits(dir); } } /** * Gets the DatasetCurveFitter currently selected in the DataTool. * * @return the selected DataSetCurveFitter */ public DatasetCurveFitter getSelectedCurveFitter() { Window win = this.getOwner(); if (win!=null && win instanceof DataTool) { DataTool dataTool = (DataTool)win; DataToolTab tab = dataTool.getSelectedTab(); if (tab!=null) { return tab.curveFitter; } } return null; } /** * Refreshes the dropdown with names of the available fits. * * @param name the selected fit name */ public void refreshDropdown(String name) { if (name==null) { name = defaultFitName; } deleteFitButton.setEnabled(!getPanelNames().isEmpty()); if (getPanelNames().isEmpty()) { String label = ToolsRes.getString("FitFunctionPanel.Label"); //$NON-NLS-1$ dropdownLabel.setText(label+":"); //$NON-NLS-1$ } super.refreshDropdown(name); } /** * Adds a fit function unless already added or loaded. * * @param f the fit function to add * @return true if added now or previously */ public boolean addFitFunction(KnownFunction f) { if (f instanceof UserFunction) { String name = f.getName(); if (addedFits.contains(name)) return true; // if a panel exists with the same original name, don't add this fit for (String next: getPanelNames()) { FitFunctionPanel panel = (FitFunctionPanel)getPanel(next); if (name.equals(panel.originalName)) { return false; } } FitFunctionPanel panel = addFitFunctionPanel((UserFunction)f); panel.originalName = name; addedFits.add(name); } else if (f instanceof KnownPolynomial) { UserFunction uf = new UserFunction((KnownPolynomial)f); return addFitFunction(uf); } return true; } /** * Loads fit functions from an XML file chosen by the user. * * @return the path to the file opened, or null if none */ private String loadFits() { if (chooser==null) { chooser = OSPRuntime.getChooser(); for (FileFilter filter: chooser.getChoosableFileFilters()) { if (filter.getDescription().toLowerCase().indexOf("xml")>-1) { //$NON-NLS-1$ chooser.setFileFilter(filter); break; } } } int result = chooser.showOpenDialog(FitBuilder.this); if(result==JFileChooser.APPROVE_OPTION) { OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString(); String fileName = chooser.getSelectedFile().getAbsolutePath(); return loadFits(fileName, false); } return null; } /** * Loads fit functions from an XML file. * * @param path the path to the XML file * @param loadAll true to load all fit functions defined in the file, false to let the user choose * @return the path to the file opened, or null if failed */ private String loadFits(String path, boolean loadAll) { if (path==null) return loadFits(); XMLControl control = new XMLControlElement(path); if (control.failedToRead()) { JOptionPane.showMessageDialog(FitBuilder.this, ToolsRes.getString("Dialog.Invalid.Message"), //$NON-NLS-1$ ToolsRes.getString("Dialog.Invalid.Title"), //$NON-NLS-1$ JOptionPane.ERROR_MESSAGE); return null; } Class<?> type = control.getObjectClass(); if (FitBuilder.class.isAssignableFrom(type)) { // choose fits to load if (loadAll || chooseFitFunctions(control, "Load")) { //$NON-NLS-1$ control.loadObject(this); } } else { JOptionPane.showMessageDialog(FitBuilder.this, ToolsRes.getString("DatasetCurveFitter.FitBuilder.Dialog.WrongType.Message"), //$NON-NLS-1$ ToolsRes.getString("DatasetCurveFitter.FitBuilder.Dialog.WrongType.Title"), //$NON-NLS-1$ JOptionPane.ERROR_MESSAGE); } return path; } /** * Saves fit functions to an XML file chosen by the user. * * @return the path to the file saved, or null if cancelled or failed */ private String saveFits() { XMLControl control = new XMLControlElement(this); // choose fits to save if (chooseFitFunctions(control, "Save")) { //$NON-NLS-1$ if (chooser==null) { chooser = OSPRuntime.getChooser(); for (FileFilter filter: chooser.getChoosableFileFilters()) { if (filter.getDescription().toLowerCase().indexOf("xml")>-1) { //$NON-NLS-1$ chooser.setFileFilter(filter); break; } } } FontSizer.setFonts(chooser, FontSizer.getLevel()); int result = chooser.showSaveDialog(FitBuilder.this); 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 isSelected = JOptionPane.showConfirmDialog(FitBuilder.this, ToolsRes.getString("Tool.Dialog.ReplaceFile.Message")+" "+file.getName()+"?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ToolsRes.getString("Tool.Dialog.ReplaceFile.Title"), //$NON-NLS-1$ JOptionPane.YES_NO_CANCEL_OPTION); if(isSelected!=JOptionPane.YES_OPTION) { return null; } } return saveFits(file.getAbsolutePath(), control); } } return null; } /** * Saves fit functions to an XML file. * * @param path the file path * @param control a FitBuilder XMLControl * @return the path to the file saved */ private String saveFits(String path, XMLControl control) { if (path==null) return saveFits(); // add .xml extension if none but don't replace other extensions if(XML.getExtension(path)==null) { path += ".xml"; //$NON-NLS-1$ } if (control==null || control.getObjectClass()!=this.getClass()) { control = new XMLControlElement(this); } control.write(path); return path; } /** * Loads fit functions from all FitBuilder XMLControl files found in a specified directory. * * @param dirPath the directory path */ private void autoloadFits(String dirPath) { if (dirPath==null) return; File dir = new File(dirPath); if (!dir.exists()) return; File[] files = dir.listFiles(xmlFilter); if (files!=null) { for (File file: files) { XMLControl control = new XMLControlElement(file.getPath()); if (control.failedToRead()) { continue; } Class<?> type = control.getObjectClass(); if (type!=null && FitBuilder.class.isAssignableFrom(type)) { // copy the control for modification if any functions are autoload_off XMLControl copyControl = new XMLControlElement(control); String filePath = XML.forwardSlash(file.getAbsolutePath()); eliminateExcludedFunctions(copyControl, filePath); copyControl.loadObject(this); } } } } /** * Finds fit functions in all FitBuilder XMLControl files in a specified directory. * Each fit function is String[] {String name, String expression, String description} * * @param dirPath the directory path * @return a map of filePath to list of fit functions */ private Map<String, ArrayList<String[]>> findFitFunctions(String dirPath) { Map<String, ArrayList<String[]>> results = new TreeMap<String, ArrayList<String[]>>(); if (dirPath==null) return results; File dir = new File(dirPath); if (!dir.exists()) return results; File[] files = dir.listFiles(xmlFilter); if (files!=null) { for (File file: files) { XMLControl control = new XMLControlElement(file.getPath()); if (control.failedToRead()) { continue; } Class<?> type = control.getObjectClass(); if (type!=null && FitBuilder.class.isAssignableFrom(type)) { ArrayList<String[]> functions = new ArrayList<String[]>(); // look through XMLControl for fit functions for (Object next: control.getPropertyContent()) { if (next instanceof XMLProperty && ((XMLProperty)next).getPropertyName().equals("functions")) { //$NON-NLS-1$ // found FitFunctionPanels XMLControl[] panels = ((XMLProperty)next).getChildControls(); for (XMLControl panelControl: panels) { String name = panelControl.getString("name"); //$NON-NLS-1$ String expression = panelControl.getString("description"); //$NON-NLS-1$ String[] data = new String[] {name, expression}; functions.add(data); } break; } } // add entry to the results map results.put(file.getName(), functions); } } } return results; } /** * Eliminates unwanted function entries from a FitBuilder XMLControl. * Typical control: * * <object class="org.opensourcephysics.tools.FitBuilder"> * <property name="functions" type="collection" class="java.util.ArrayList"> * <property name="item" type="object"> * <object class="org.opensourcephysics.tools.FitFunctionPanel"> * <property name="name" type="string">NaturalLog</property> * <property name="description" type="string">y = ln(x)</property> * <property name="user_parameters" type="array" class="[Lorg.opensourcephysics.tools.Parameter;"/> * <property name="function_editor" type="object"> * <object class="org.opensourcephysics.tools.UserFunctionEditor"> * <property name="main_functions" type="array" class="[Lorg.opensourcephysics.tools.UserFunction;"> * <property name="[0]" type="object"> * <object class="org.opensourcephysics.tools.UserFunction"> * <property name="name" type="string">NaturalLog</property> * <property name="name_editable" type="boolean">true</property> * <property name="parameter_names" type="array" class="[Ljava.lang.String;"/> * <property name="parameter_values" type="array" class="[D"/> * <property name="parameter_descriptions" type="array" class="[Ljava.lang.String;"/> * <property name="variables" type="array" class="[Ljava.lang.String;"> * <property name="[0]" type="string">x</property> * </property> * <property name="expression" type="string">ln(x)</property> * </object> * </property> * </property> * </object> * </property> * <property name="autoload_off_NaturalLog" type="boolean">true</property> * </object> * </property> * </property> * </object> * * @param fitBuilderControl the XMLControl to modify * @param filePath the path to the XML file read by the XMLControl */ protected void eliminateExcludedFunctions(XMLControl fitBuilderControl, String filePath) { for (Object obj: fitBuilderControl.getPropertyContent()) { if (obj instanceof XMLProperty && ((XMLProperty)obj).getPropertyName().equals("functions")) { //$NON-NLS-1$ // found fitFunctionPanels XMLProperty prop = (XMLProperty)obj; List<Object> items = prop.getPropertyContent(); ArrayList<Object> toRemove = new ArrayList<Object>(); XMLControl[] panels = prop.getChildControls(); for (int i=0; i<panels.length; i++) { XMLControl panelControl = panels[i]; String name = panelControl.getString("name"); //$NON-NLS-1$ if (isFunctionExcluded(filePath, name)) { toRemove.add(items.get(i)); } } for (Object next: toRemove) { items.remove(next); } } } } /** * Determines if a named function is excluded from autoloading. * * @param filePath the path to the file defining the function * @param functionName the function name * @return true if the function is excluded */ private boolean isFunctionExcluded(String filePath, String functionName) { String[] functions = autoloadMap.get(filePath); if (functions==null) return false; for (String name: functions) { if (name.equals("*")) return true; //$NON-NLS-1$ if (name.equals(functionName)) return true; } return false; } /** * Refreshes the GUI. */ protected void refreshGUI() { super.refreshGUI(); setTitle(ToolsRes.getString("DatasetCurveFitter.FitBuilder.Title")); //$NON-NLS-1$ if (getPanelNames().isEmpty()) { String label = ToolsRes.getString("FitFunctionPanel.Label"); //$NON-NLS-1$ dropdownLabel.setText(label+":"); //$NON-NLS-1$ } if (saveButton!=null) { saveButton.setEnabled(!getPanelNames().isEmpty()); loadButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.FitBuilder.Button.Load.Tooltip")); //$NON-NLS-1$ saveButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.FitBuilder.Button.Save.Tooltip")); //$NON-NLS-1$ FitFunctionPanel panel = (FitFunctionPanel)getSelectedPanel(); deleteFitButton.setEnabled(!getPanelNames().isEmpty() && panel.originalName==null); newFitButton.setText(ToolsRes.getString("DatasetCurveFitter.Button.NewFit.Text")); //$NON-NLS-1$ newFitButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.Button.NewFit.Tooltip")); //$NON-NLS-1$ deleteFitButton.setText(ToolsRes.getString("DatasetCurveFitter.Button.DeleteFit.Text")); //$NON-NLS-1$ deleteFitButton.setToolTipText(ToolsRes.getString("DatasetCurveFitter.Button.DeleteFit.Tooltip")); //$NON-NLS-1$ DatasetCurveFitter fitter = getSelectedCurveFitter(); cloneFitButton.setEnabled(fitter!=null); autoloadButton.setText(ToolsRes.getString("FitBuilder.Button.Autoload")+"..."); //$NON-NLS-1$ //$NON-NLS-2$ autoloadButton.setToolTipText(ToolsRes.getString("FitBuilder.Button.Autoload.Tooltip")); //$NON-NLS-1$ } } /** * Displays a dialog with a list of fit functions to load or save. * * @param control a FitBuilder XMLControl * @param description a description of the purpose (ie load or save) * @return true if not cancelled by the user */ protected boolean chooseFitFunctions(XMLControl control, String description) { ListChooser listChooser = new ListChooser( ToolsRes.getString("DatasetCurveFitter.FitBuilder."+description+".Title"), //$NON-NLS-1$ //$NON-NLS-2$ ToolsRes.getString("DatasetCurveFitter.FitBuilder."+description+".Message"), //$NON-NLS-1$ //$NON-NLS-2$ this); // choose the elements and load the function tool ArrayList<XMLControl> originals = new ArrayList<XMLControl>(); ArrayList<XMLControl> choices = new ArrayList<XMLControl>(); ArrayList<String> names = new ArrayList<String>(); ArrayList<String> expressions = new ArrayList<String>(); for (Object next: control.getPropertyContent()) { if (next instanceof XMLProperty) { XMLProperty prop = (XMLProperty)next; for (Object obj: prop.getPropertyContent()) { if (obj instanceof XMLProperty) { XMLProperty f = (XMLProperty)obj; XMLControl function = f.getChildControls()[0]; originals.add(function); choices.add(function); names.add(function.getString("name")); //$NON-NLS-1$ String desc = function.getString("description"); //$NON-NLS-1$ expressions.add(desc); } } } } // select all by default boolean[] selected = new boolean[choices.size()]; for (int i = 0; i<selected.length; i++) { selected[i] = true; } if (listChooser.choose(choices, names, expressions, selected)) { // compare choices with originals and remove unwanted object content for (XMLControl next: originals) { if (!choices.contains(next)) { XMLProperty prop = next.getParentProperty(); XMLProperty parent = prop.getParentProperty(); parent.getPropertyContent().remove(prop); } } return true; } return false; } /** * Adds a fit function panel. * * @param f the fit function to add * @return the fit function panel */ protected FitFunctionPanel addFitFunctionPanel(UserFunction f) { UserFunctionEditor editor = new UserFunctionEditor(); editor.setMainFunctions(new UserFunction[] {f}); FitFunctionPanel panel = new FitFunctionPanel(editor); return (FitFunctionPanel)addPanel(f.getName(), panel); } /** * Gets the autoload manager, creating it the first time called. * * @return the autoload manageer */ protected AutoloadManager getAutoloadManager() { if (autoloadManager==null) { autoloadManager = new AutoloadManager(this); // center on screen Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); int x = (dim.width - autoloadManager.getBounds().width) / 2; int y = (dim.height - autoloadManager.getBounds().height) / 2; autoloadManager.setLocation(x, y); } autoloadManager.setFontLevel(FontSizer.getLevel()); return autoloadManager; } //-------------------------------- static methods --------------------------- public static String localize(String functionName) { String s = ToolsRes.getString("Function."+functionName+".Name"); //$NON-NLS-1$ //$NON-NLS-2$ if (!s.startsWith("!")) return s; //$NON-NLS-1$ return functionName; } /** * Gets the autoload search paths. * * @return the search paths */ protected static Collection<String> getInitialSearchPaths() { if (initialAutoloadSearchPaths.isEmpty()) { if (preferredAutoloadSearchPaths!=null) { for (String next: preferredAutoloadSearchPaths) { initialAutoloadSearchPaths.add(next); } } else { for (String next: OSPRuntime.getDefaultSearchPaths()) { initialAutoloadSearchPaths.add(next); } } } return initialAutoloadSearchPaths; } //-------------------------------- inner classes --------------------------- /** * An AutoloadManager for DataFunctions. */ class AutoloadManager extends AbstractAutoloadManager { /** * Constructor for a dialog. * * @param dialog the dialog (DataBuilder) */ public AutoloadManager(JDialog dialog) { super(dialog); } @Override public void setVisible(boolean vis) { super.setVisible(vis); if (!vis) { // save non-default search paths in preferredAutoloadSearchPaths Collection<String> searchPaths = getSearchPaths(); Collection<String> defaultPaths = OSPRuntime.getDefaultSearchPaths(); boolean isDefault = searchPaths.size()==defaultPaths.size(); for (String next: searchPaths) { isDefault = isDefault && defaultPaths.contains(next); } if (isDefault) { preferredAutoloadSearchPaths = null; } else { preferredAutoloadSearchPaths = searchPaths.toArray(new String[searchPaths.size()]); } OSPRuntime.setPreference("autoload_search_paths", preferredAutoloadSearchPaths); //$NON-NLS-1$ // clean up autoloadMap of excluded autoloadable functions for (Iterator<String> it = autoloadMap.keySet().iterator(); it.hasNext();) { String filePath = it.next(); String parentPath = XML.getDirectoryPath(filePath); boolean keep = false; for (String dir: searchPaths) { keep = keep || parentPath.equals(dir); } if (!keep || !new File(filePath).exists()) { it.remove(); } } // save excluded autoloadable functions if (autoloadMap.isEmpty()) { OSPRuntime.setPreference("autoload_exclusions", null); //$NON-NLS-1$ } else { String[][] autoloadData = new String[autoloadMap.size()][]; int i = 0; for (String filePath: autoloadMap.keySet()) { String[] functions = autoloadMap.get(filePath); String[] fileAndFunctions = new String[functions.length+1]; fileAndFunctions[0] = filePath; System.arraycopy(functions, 0, fileAndFunctions, 1, functions.length); autoloadData[i] = fileAndFunctions; i++; } OSPRuntime.setPreference("autoload_exclusions", autoloadData); //$NON-NLS-1$ } OSPRuntime.savePreferences(); } } /** * Sets the selection state of a function. * * @param filePath the path to the file defining the function * @param function the function {name, expression, optional descriptor} * @param select true to select the function */ protected void setFunctionSelected(String filePath, String[] function, boolean select) { String[] oldExclusions = autoloadMap.get(filePath); String[] newExclusions = null; if (!select) { // create or add entry to newExclusions if (oldExclusions==null) { newExclusions = new String[] {function[0]}; } else { int n = oldExclusions.length; newExclusions = new String[n+1]; System.arraycopy(oldExclusions, 0, newExclusions, 0, n); newExclusions[n] = function[0]; } } else if (oldExclusions!=null){ // remove entry int n = oldExclusions.length; if (n>1) { ArrayList<String> exclusions = new ArrayList<String>(); for (String f: oldExclusions) { if (f.equals(function[0])) continue; exclusions.add(f); } newExclusions = exclusions.toArray(new String[exclusions.size()]); } } autoloadMap.remove(filePath); if (newExclusions!=null) { autoloadMap.put(filePath, newExclusions); } refreshAutoloadData(); // reload fits for (String dir: getSearchPaths()) { autoloadFits(dir); } } /** * Gets the selection state of a function. * * @param filePath the path to the file defining the function * @param function the function {name, expression, optional descriptor} * @return true if the function is selected */ protected boolean isFunctionSelected(String filePath, String[] function) { String[] functions = autoloadMap.get(filePath); if (functions==null) return true; for (String name: functions) { if (name.equals("*")) return false; //$NON-NLS-1$ if (name.equals(function[0])) return false; } return true; } /** * Sets the selection state of a file. * * @param filePath the path to the file * @param select true to select the file */ protected void setFileSelected(String filePath, boolean select) { autoloadMap.remove(filePath); if (!select) { String[] function = new String[] {"*"}; //$NON-NLS-1$ autoloadMap.put(filePath, function); } refreshAutoloadData(); // reload fits for (String dir: getSearchPaths()) { autoloadFits(dir); } } /** * Gets the selection state of a file. * * @param filePath the path to the file * @return TristateCheckBox.SELECTED, NOT_SELECTED or PART_SELECTED */ protected TristateCheckBox.State getFileSelectionState(String filePath) { String[] functions = autoloadMap.get(filePath); if (functions==null) return TristateCheckBox.SELECTED; if (functions[0].equals("*")) return TristateCheckBox.NOT_SELECTED; //$NON-NLS-1$ return TristateCheckBox.PART_SELECTED; } /** * Gets the collection of search paths. * * @return the search paths */ @Override public Collection<String> getSearchPaths() { Collection<String> paths = super.getSearchPaths(); if (paths.isEmpty() && !initialized) { initialized = true; for (String next: getInitialSearchPaths()) { paths.add(next); addSearchPath(next); } } return paths; } /** * Refreshes the autoload data. */ @Override protected void refreshAutoloadData() { final Map<String, Map<String, ArrayList<String[]>>> data = new TreeMap<String, Map<String, ArrayList<String[]>>>(); for (String path: getSearchPaths()) { Map<String, ArrayList<String[]>> functionMap = findFitFunctions(path); data.put(path, functionMap); } setAutoloadData(data); } /** * Refreshes the GUI. */ protected void refreshGUI() { refreshAutoloadData(); super.refreshGUI(); String title = FitBuilder.this.getTitle()+" "+getTitle(); //$NON-NLS-1$ setTitle(title); setInstructions(ToolsRes.getString("FitBuilder.Instructions.SelectToAutoload") //$NON-NLS-1$ + "\n\n"+ToolsRes.getString("FitBuilder.Instructions.WhereDefined") //$NON-NLS-1$ //$NON-NLS-2$ +" "+ToolsRes.getString("FitBuilder.Instructions.HowToAddFunction") //$NON-NLS-1$ //$NON-NLS-2$ +" "+ToolsRes.getString("FitBuilder.Instructions.HowToAddDirectory")); //$NON-NLS-1$ //$NON-NLS-2$ } } }