ai.aitia.meme.paramsweep.gui.Page_Parameters.java Source code

Java tutorial

Introduction

Here is the source code for ai.aitia.meme.paramsweep.gui.Page_Parameters.java

Source

/*******************************************************************************
 * Copyright (C) 2006-2013 AITIA International, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package ai.aitia.meme.paramsweep.gui;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import ai.aitia.meme.events.HybridAction;
import ai.aitia.meme.events.IHybridActionListener;
import ai.aitia.meme.gui.ExpandedEditor;
import ai.aitia.meme.gui.Wizard;
import ai.aitia.meme.gui.Wizard.Button;
import ai.aitia.meme.gui.Wizard.IArrowsInHeader;
import ai.aitia.meme.gui.Wizard.IWizardPage;
import ai.aitia.meme.paramsweep.ParameterSweepWizard;
import ai.aitia.meme.paramsweep.batch.IModelInformation.ModelInformationException;
import ai.aitia.meme.paramsweep.batch.output.RecordableInfo;
import ai.aitia.meme.paramsweep.generator.WizardSettingsManager;
import ai.aitia.meme.paramsweep.gui.info.MasonChooserParameterInfo;
import ai.aitia.meme.paramsweep.gui.info.ParameterInfo;
import ai.aitia.meme.paramsweep.internal.platform.IGUIController;
import ai.aitia.meme.paramsweep.internal.platform.IGUIController.RunOption;
import ai.aitia.meme.paramsweep.internal.platform.InfoConverter;
import ai.aitia.meme.paramsweep.internal.platform.PlatformSettings;
import ai.aitia.meme.paramsweep.plugin.IIntelliContext;
import ai.aitia.meme.paramsweep.utils.ParameterEnumeration;
import ai.aitia.meme.paramsweep.utils.ParameterParserException;
import ai.aitia.meme.paramsweep.utils.Util;
import ai.aitia.meme.paramsweep.utils.Utilities;
import ai.aitia.meme.paramsweep.utils.WizardLoadingException;
import ai.aitia.meme.utils.FormsUtils;
import ai.aitia.meme.utils.FormsUtils.Separator;
import ai.aitia.meme.utils.GUIUtils;

import com.jgoodies.forms.layout.CellConstraints;

import edu.thirdparty.DnDTree;
import edu.thirdparty.DnDTree.DnDTreeCellRenderer;
import edu.thirdparty.DnDTree.DnDTreeDropSuccessfulEvent;
import edu.thirdparty.DnDTree.DnDTreeDropSuccessfulListener;

/** This class provides the Parameters page of the Parameter Sweep Wizard. */
public class Page_Parameters extends JPanel implements IWizardPage, IArrowsInHeader, ActionListener,
        IHybridActionListener, TreeSelectionListener, FocusListener, DnDTreeDropSuccessfulListener {

    //===============================================================================
    // members

    private static final long serialVersionUID = 1L;

    private static final String orderPart1 = "Select a parameter from the tree";
    private static final String orderPart2 = "to modify its settings.";

    /** The owner of the page. */
    private ParameterSweepWizard owner = null;
    /** The list of information objects of the parameters. */
    private List<ParameterInfo> parameters = null;
    /** The names of the parameters. */
    private String[] initParamResult = null;
    /** The names of the parameters of the original model. */
    private String[] originalInitParamResult = null;
    /** The list of information objects of the new (defined by this wizard) parameters. */
    private List<ParameterInfo> newParameters = null;

    HybridAction moveUpAction = new HybridAction(this, "Move up", null);
    HybridAction moveDownAction = new HybridAction(this, "Move down", null);
    HybridAction editAction = new HybridAction(this, "Edit", null);

    /** The edited node of the parameter tree. */
    private DefaultMutableTreeNode editedNode = null;

    private IntelliContext intelliContext = null;
    private boolean modelInformationException = false;

    //===============================================================================
    // GUI members

    private JPanel content = null;
    private JPanel left = null;
    private JPanel leftFirst = new JPanel(new BorderLayout());
    private JPanel leftSecond = new JPanel();
    private JLabel text1 = new JLabel(orderPart1);
    private JLabel text2 = new JLabel(orderPart2);
    private JLabel runsLabel = new JLabel("Runs: ");
    private JTextField runsField = new JTextField("");
    private JRadioButton constDef = new JRadioButton("Constant");
    private JRadioButton listDef = new JRadioButton("List");
    private JRadioButton incrDef = new JRadioButton("Increment");
    private JPanel leftTop = null;
    private JButton modifyButton = new JButton("Modify");
    private JButton cancelButton = new JButton("Cancel");
    private JButton addEnumButton = new JButton(">>");
    private JButton removeEnumButton = new JButton("<<");
    private JTextField constDefField = new JTextField();
    private JPanel constDefPanel = null;
    private JPanel enumListPanel = null;
    private JPanel enumConstPanel = null;
    private JButton browseFileButton = new JButton(FileSystemView.getFileSystemView().getSystemIcon(new File(".")));
    private JTextArea listDefArea = new JTextArea();
    private DefaultListModel<String> leftEnumValueModel = new DefaultListModel<String>();
    private DefaultListModel<String> rightEnumValueModel = new DefaultListModel<String>();
    private DefaultComboBoxModel<String> enumComboBoxModel = new DefaultComboBoxModel<String>();
    private JList leftEnumValueList = new JList<String>(leftEnumValueModel);
    private JList rightEnumValueList = new JList<String>(rightEnumValueModel);
    private JScrollPane listDefScr = new JScrollPane(listDefArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    private JScrollPane leftEnumValuePane = new JScrollPane(leftEnumValueList,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    private JScrollPane RightEnumValuePane = new JScrollPane(rightEnumValueList,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    private JComboBox<String> enumComboBox = new JComboBox<String>(enumComboBoxModel);
    private JPanel listDefPanel = null;
    private JTextField incrStartValueField = new JTextField();
    private JTextField incrEndValueField = new JTextField();
    private JTextField incrStepField = new JTextField();
    private JPanel incrDefPanel = null;
    private JPanel leftMiddle = new JPanel(new CardLayout());
    private JPanel leftBottom = null;
    private JButton newParameterButton = new JButton("Add new parameters...");
    private DefaultMutableTreeNode root = new DefaultMutableTreeNode("Parameter file");
    private DnDTree outputTree = new DnDTree(new DefaultTreeModel(root)) {
        private static final long serialVersionUID = -3266082500122393494L;

        @Override
        protected void illegalDrop(Exception e) {
            Utilities.userAlert(this, "Swap not supported.");
        }

        //@Override
        protected boolean mouseReleasedCondition() {
            return editedNode == null || modify();
        }

    };
    private JScrollPane treeScr = new JScrollPane(outputTree, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    private JButton moveUpButton = new JButton(moveUpAction);
    private JButton moveDownButton = new JButton(moveDownAction);
    private JButton editButton = new JButton(editAction);
    private JPanel right = null;
    private JButton newParameterButtonCopy = new JButton("Add new parameters...");
    private JLabel numberOfRunsLabel = new JLabel(" A total of 1 run.");

    //===============================================================================
    // methods

    //----------------------------------------------------------------------------------------------------
    /** Constructor.
     * @param owner the owner of the page
     */
    public Page_Parameters(ParameterSweepWizard owner) {
        this.owner = owner;
        outputTree.setToggleClickCount(5);
        layoutGUI();
        initialize();
    }

    //-------------------------------------------------------------------------------
    public List<ParameterInfo> getParameters() {
        return parameters;
    }

    /** Returns the root node of the parameters tree. */
    public DefaultMutableTreeNode getParameterTreeRoot() {
        return root;
    }

    public String[] getInitParamResult() {
        return initParamResult;
    }

    public List<ParameterInfo> getNewParametersList() {
        return newParameters;
    }

    public JButton getNewParametersButton() {
        return newParameterButtonCopy;
    }

    //-------------------------------------------------------------------------------
    /** Checks whether a constant parameter has child in the tree which results 
     *  an illegal parameter file. 
     * @return the name of the first invalid constant paramter (or null)
     */
    public String checkConstants() {
        String res = null;
        ParameterEnumeration e = new ParameterEnumeration(root);
        while (e.hasMoreElements()) {
            DefaultMutableTreeNode node = e.nextElement();
            if (node.equals(root))
                continue;
            ParameterInfo info = (ParameterInfo) node.getUserObject();
            if (info.isConstant() && node.getChildCount() > 0)
                return info.getName();
        }
        return res;
    }

    //----------------------------------------------------------------------------------------------------
    public boolean needTreeFormatWarning() {
        int nrOfNonConstants = 0;
        for (int i = 0; i < root.getChildCount(); ++i) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
            ParameterInfo info = (ParameterInfo) node.getUserObject();
            if (!info.isConstant())
                nrOfNonConstants++;
            if (nrOfNonConstants > 1)
                return true;
        }
        return false;
    }

    //-------------------------------------------------------------------------------
    /** Saves the page-related model settings to the XML node <code>node</code>. This
     *  method is part of the model settings storing performed by {@link ai.aitia.meme.paramsweep.generator.WizardSettingsManager 
     *  WizardSettingsManager}.
     * @throws TransformerException 
     * @throws ParserConfigurationException 
     */
    public void save(Node node) throws ParserConfigurationException, TransformerException {
        Document document = node.getOwnerDocument();

        Element element = document.createElement(WizardSettingsManager.PARAMETER_FILE);
        element.appendChild(document.createTextNode(PlatformSettings.generateParameterTreeOutput(root)));
        node.appendChild(element);

        if (newParameters != null) {
            Element np = document.createElement(WizardSettingsManager.NEW_PARAMETERS);
            for (ParameterInfo pi : newParameters) {
                element = document.createElement(WizardSettingsManager.PARAMETER);
                element.setAttribute(WizardSettingsManager.TYPE, pi.getType());
                element.setAttribute(WizardSettingsManager.JAVA_TYPE, pi.getJavaType().getName());
                String name = pi.getName();
                RecordableInfo dummy = new RecordableInfo(name, Integer.TYPE, null, name);
                try {
                    if (owner.getModelInformation().getRecordables().indexOf(dummy) == -1)
                        name = Util.uncapitalize(name);
                } catch (ModelInformationException e) {
                    throw new IllegalStateException(e);
                }
                element.appendChild(document.createTextNode(name));
                np.appendChild(element);
            }
            node.appendChild(np);
        }
    }

    //-------------------------------------------------------------------------------
    /** Loads the page-related model settings from the XML element <code>element</code>. This
     *  method is part of the model settings retrieving performed by {@link ai.aitia.meme.paramsweep.generator.WizardSettingsManager 
     *  WizardSettingsManager}.
     * @throws WizardLoadingException if the XML document is invalid
     */
    public void load(Element element) throws WizardLoadingException {
        NodeList nl = element.getElementsByTagName(WizardSettingsManager.NEW_PARAMETERS);
        if (nl == null || nl.getLength() == 0)
            newParameters = null;
        else {
            NodeList nodes = ((Element) nl.item(0)).getElementsByTagName(WizardSettingsManager.PARAMETER);
            if (nodes == null || nodes.getLength() == 0)
                throw new WizardLoadingException(true, "missing node: " + WizardSettingsManager.PARAMETER);
            newParameters = new ArrayList<ParameterInfo>(nodes.getLength());
            for (int i = 0; i < nodes.getLength(); ++i) {
                Element param = (Element) nodes.item(i);
                String type = param.getAttribute(WizardSettingsManager.TYPE);
                if (type == null || type.equals(""))
                    throw new WizardLoadingException(true,
                            "missing 'type' attribute at node: " + WizardSettingsManager.PARAMETER);
                String javaTypeStr = param.getAttribute(WizardSettingsManager.JAVA_TYPE);
                if (javaTypeStr == null || "".equals(javaTypeStr))
                    throw new WizardLoadingException(true,
                            "missing 'java_type' attribute at node: " + WizardSettingsManager.PARAMETER);
                NodeList content = param.getChildNodes();
                if (content == null || content.getLength() == 0)
                    throw new WizardLoadingException(true,
                            "missing content at node: " + WizardSettingsManager.PARAMETER);
                String name = ((Text) content.item(0)).getNodeValue();
                Class<?> javaType = null;
                try {
                    javaType = Utilities.toClass(owner.getClassLoader(), javaTypeStr);
                } catch (ClassNotFoundException e) {
                    throw new WizardLoadingException(true, "invalid type at parameter: " + name);
                }
                ParameterInfo pi = new ParameterInfo(name, type, javaType);
                if (!pi.isNumeric() && !pi.isBoolean() && !pi.getType().equals("String"))
                    throw new WizardLoadingException(true,
                            "invalid 'type' attribute at node: " + WizardSettingsManager.PARAMETER);
                newParameters.add(pi);
            }
        }

        clearTree();
        parameters = createParameters();

        nl = null;
        nl = element.getElementsByTagName(WizardSettingsManager.PARAMETER_FILE);
        if (nl == null || nl.getLength() == 0)
            throw new WizardLoadingException(true, "missing node: " + WizardSettingsManager.PARAMETER_FILE);
        NodeList content = nl.item(0).getChildNodes();
        if (content == null || content.getLength() == 0)
            throw new WizardLoadingException(true,
                    "missing content at node: " + WizardSettingsManager.PARAMETER_FILE);
        String paramFileContent = ((Text) content.item(0)).getNodeValue();
        try {
            root = PlatformSettings.parseParameterFile(parameters, paramFileContent);
            outputTree.setModel(new DefaultTreeModel(root));
            outputTree.expandRow(0);
        } catch (ParameterParserException e) {
            throw new WizardLoadingException(true, e);
        }
        if (cancelButton.isEnabled())
            cancelButton.doClick();
        setGlobalRunsField();
        setNumberOfRuns();
    }

    //----------------------------------------------------------------------------------------------------
    public void setGlobalRuns() {
        final long runs = parseGlobalRuns();
        ParameterEnumeration pe = new ParameterEnumeration(root);
        while (pe.hasMoreElements()) {
            DefaultMutableTreeNode node = pe.nextElement();
            if (root.equals(node))
                continue;
            ParameterInfo info = (ParameterInfo) node.getUserObject();
            info.setRuns(runs);
        }
    }

    //----------------------------------------------------------------------------------------------------
    public void transformIncrementsIfNeed() {
        ParameterEnumeration pe = new ParameterEnumeration(root);
        for (DefaultMutableTreeNode node = pe.nextElement(); pe.hasMoreElements(); node = pe.nextElement()) {
            if (root.equals(node))
                continue;
            ParameterInfo info = (ParameterInfo) node.getUserObject();
            if (info.getDefinitionType() == ParameterInfo.INCR_DEF)
                info.transformIfNeed();
        }
    }

    //===============================================================================
    // interface implementations

    //----------------------------------------------------------------------------------------------------
    public String getInfoText(Wizard w) {
        return w.getArrowsHeader(
                "Specify input parameter values: Set the number of runs for each parameter value, define the parameter space and"
                        + " embed parameter runs into each other");
    }

    //-------------------------------------------------------------------------------
    public Container getPanel() {
        return this;
    }

    public String getTitle() {
        return "Parameters";
    }

    //----------------------------------------------------------------------------------------------------
    public boolean onButtonPress(Button b) {
        boolean enabled = isEnabled(b);
        if (enabled) {
            if (b == Button.CANCEL || editedNode == null || modify())
                return true;
        }
        return false;
    }

    //----------------------------------------------------------------------------------------------------
    public boolean isEnabled(Button b) {
        if (modelInformationException && (b == Button.NEXT || b == Button.FINISH))
            return false;
        return PlatformSettings.isEnabledForPageParameters(owner, b);
    }

    //-------------------------------------------------------------------------------
    public void onPageChange(boolean show) {
        if (show) {
            if (owner.getModelState() == ParameterSweepWizard.ERROR)
                return;
            initializePageForPlatform();
            if (owner.getModelState() == ParameterSweepWizard.NEW_MODEL) {
                modelInformationException = false;
                // build the tree
                clearTree();
                parameters = createParameters();
                if (parameters == null)
                    return;
                if (owner.getParameterFile() != null && owner.getParameterFile().exists()) {
                    try {
                        root = PlatformSettings.parseParameterFile(parameters, owner.getParameterFile());
                        root.setUserObject(new String(owner.getParameterFile().getName()));
                        setGlobalRunsField();
                        outputTree.setModel(new DefaultTreeModel(root));
                        outputTree.expandRow(0);
                    } catch (ParameterParserException e) {
                        Utilities.userAlert(owner, "Cannot initialize from the defined parameter file.",
                                "Reason: " + Util.getLocalizedMessage(e));
                        e.printStackTrace(ParameterSweepWizard.getLogStream());
                        createDefaultTree();
                    }
                } else
                    createDefaultTree();
                enableDisableSettings(false);
                modifyButton.setEnabled(false);
                owner.setModelState(ParameterSweepWizard.NEW_RECORDERS);
            }
            if (owner.getParameterFile() != null && owner.isParameterFileChanged()) {
                if (owner.getModelState() != ParameterSweepWizard.NEW_MODEL && owner.getParameterFile().exists()) {
                    try {
                        root = PlatformSettings.parseParameterFile(parameters, owner.getParameterFile());
                        root.setUserObject(new String(owner.getParameterFile().getName()));
                        setGlobalRunsField();
                        outputTree.setModel(new DefaultTreeModel(root));
                        outputTree.expandRow(0);
                    } catch (ParameterParserException e) {
                        Utilities.userAlert(owner, "Cannot initialize from the defined parameter file.",
                                "Reason: " + Util.getLocalizedMessage(e));
                        e.printStackTrace(ParameterSweepWizard.getLogStream());
                    }
                }
            }
            owner.setParameterFileChanged(false);
            setNumberOfRuns();
        } else {
            if (cancelButton.isEnabled())
                cancelButton.doClick();
        }
    }

    //-------------------------------------------------------------------------------
    public void actionPerformed(ActionEvent e) {
        hybridAction(e, null);
    }

    //--------------------------------------------------------------------------------
    /** This method is intended to be a common place for handling "related" actionPerformed()
     *  messages (here "related" usually means that belong to the same window).
     * @param a Non-null only if this actionPerformed() message is originated from a
     *           HybridAction object.     
     */
    public void hybridAction(ActionEvent e, HybridAction a) {
        if (a != null) {
            if (a == moveUpAction) {
                if (editedNode == null || modify()) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) outputTree.getSelectionPath()
                            .getLastPathComponent();
                    DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                    if (parent == null || parent.getFirstChild().equals(node))
                        return;
                    int index = parent.getIndex(node);
                    DefaultTreeModel treemodel = (DefaultTreeModel) outputTree.getModel();
                    treemodel.removeNodeFromParent(node);
                    treemodel.insertNodeInto(node, parent, index - 1);
                    outputTree.setSelectionPath(new TreePath(node.getPath()));
                }
            } else if (a == moveDownAction) {
                if (editedNode == null || modify()) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) outputTree.getSelectionPath()
                            .getLastPathComponent();
                    DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
                    if (parent == null || parent.getLastChild().equals(node))
                        return;
                    int index = parent.getIndex(node);
                    DefaultTreeModel treemodel = (DefaultTreeModel) outputTree.getModel();
                    treemodel.removeNodeFromParent(node);
                    treemodel.insertNodeInto(node, parent, index + 1);
                    outputTree.setSelectionPath(new TreePath(node.getPath()));
                }
            } else if (a == editAction) {
                if (editedNode == null || modify()) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) outputTree.getSelectionPath()
                            .getLastPathComponent();
                    if (node.equals(root))
                        return;
                    ParameterInfo info = (ParameterInfo) node.getUserObject();
                    editedNode = node;
                    outputTree.expandPath(outputTree.getSelectionPath());
                    edit(info);
                }
            }
        } else {
            String command = e.getActionCommand();
            if (command.equals("CONST")) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) outputTree.getSelectionPath()
                        .getLastPathComponent();
                if (node.equals(root))
                    return;
                ParameterInfo info = (ParameterInfo) node.getUserObject();
                CardLayout cl = (CardLayout) leftMiddle.getLayout();
                if (info instanceof MasonChooserParameterInfo || info.isEnum())
                    cl.show(leftMiddle, "ENUMCONST");
                else
                    cl.show(leftMiddle, "CONST");
            } else if (command.equals("LIST")) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) outputTree.getSelectionPath()
                        .getLastPathComponent();
                if (node.equals(root))
                    return;
                ParameterInfo info = (ParameterInfo) node.getUserObject();
                CardLayout cl = (CardLayout) leftMiddle.getLayout();
                if (info instanceof MasonChooserParameterInfo || info.isEnum())
                    cl.show(leftMiddle, "ENUMLIST");
                else
                    cl.show(leftMiddle, "LIST");
            } else if (command.equals("INCREMENT")) {
                CardLayout cl = (CardLayout) leftMiddle.getLayout();
                cl.show(leftMiddle, "INCREMENT");
            } else if (command.equals("MODIFY")) {
                browseFileButton.setVisible(false);
                modify();
            } else if (command.equals("ADD")) {
                for (Object element : leftEnumValueList.getSelectedValuesList()) {
                    rightEnumValueModel.addElement((String) element);
                }
            } else if (command.equals("REMOVE")) {
                for (Object element : rightEnumValueList.getSelectedValuesList()) {
                    rightEnumValueModel.removeElement(element);
                }
            } else if (command.equals("CANCEL")) {
                resetSettings();
                enableDisableSettings(false);
                modifyButton.setEnabled(false);
                browseFileButton.setVisible(false);
                editedNode = null;
            } else if (command.equals("RUNS_FIELD")
                    && PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL)
                constDef.grabFocus();
            else if (command.equals("CONST_FIELD") || command.equals("STEP_FIELD"))
                modifyButton.doClick();
            else if (command.equals("START_FIELD"))
                incrEndValueField.grabFocus();
            else if (command.equals("END_FIELD"))
                incrStepField.grabFocus();
            else if (command.equals("BROWSE")) {
                JFileChooser jfc = new JFileChooser();
                int val = jfc.showOpenDialog(this);
                if (val == JFileChooser.APPROVE_OPTION) {
                    File file = jfc.getSelectedFile();
                    if (file == null)
                        return;
                    constDefField.setText(file.getAbsolutePath());
                }
            } else if (command.equals("NEW_PARAMETER")) {
                int result = Utilities.askUser(owner, false, "Warning",
                        "All user defined parameter settings will be lost.", "Do you want to continue?");
                if (result == 1) { // yes
                    List<RecordableInfo> candidates = null;
                    try {
                        candidates = owner.getModelInformation().getRecordables();
                    } catch (ModelInformationException e1) {
                        Utilities.userAlert(owner, "Error while collecting new parameter candidates.",
                                "Reason: " + Util.getLocalizedMessage(e1));
                        e1.printStackTrace(ParameterSweepWizard.getLogStream());
                        return;
                    }
                    NewParametersDialog dialog = new NewParametersDialog(ParameterSweepWizard.getFrame(),
                            candidates, originalInitParamResult);
                    result = dialog.showDialog();
                    if (result == NewParametersDialog.OK_OPTION) {
                        List<ParameterInfo> oldNewParameters = newParameters == null
                                ? new ArrayList<ParameterInfo>()
                                : newParameters;
                        newParameters = dialog.getNewParameterList();
                        if (newParameters.size() == 0)
                            newParameters = null;
                        clearTree();
                        parameters = createParameters();
                        if (owner.getParameterFile() != null && owner.getParameterFile().exists()) {
                            try {
                                root = PlatformSettings.parseParameterFile(parameters, owner.getParameterFile());
                                root.setUserObject(owner.getParameterFile().getName());
                                setGlobalRunsField();
                                outputTree.setModel(new DefaultTreeModel(root));
                                outputTree.expandRow(0);
                            } catch (ParameterParserException e1) {
                                createDefaultTree();
                                Utilities.userAlert(owner, "Cannot initialize from the defined parameter file.",
                                        "Reason: " + Util.getLocalizedMessage(e1));
                                e1.printStackTrace(ParameterSweepWizard.getLogStream());
                            }
                        } else
                            createDefaultTree();
                        enableDisableSettings(false);
                        modifyButton.setEnabled(false);
                        owner.reinitializeRecordableLists(newParameters == null ? oldNewParameters
                                : Utilities.listSubtract(oldNewParameters, newParameters));
                        owner.cleanRecorders();
                        setNumberOfRuns();
                    }
                }
            }
        }
    }

    //-------------------------------------------------------------------------------
    public void valueChanged(TreeSelectionEvent e) {
        TreePath path = outputTree.getSelectionPath();
        editAction.setEnabled(path != null);
        moveUpAction.setEnabled(path != null);
        moveDownAction.setEnabled(path != null);
    }

    //------------------------------------------------------------------------------
    public IIntelliContext getIntelliContext() {
        if (intelliContext == null)
            intelliContext = new IntelliContext();
        return intelliContext;
    }

    //----------------------------------------------------------------------------------------------------
    public void focusGained(FocusEvent e) {
    }

    //----------------------------------------------------------------------------------------------------
    public void focusLost(FocusEvent e) {
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL)
            setNumberOfRuns();
    }

    //----------------------------------------------------------------------------------------------------
    public void dropSuccessful(DnDTreeDropSuccessfulEvent e) {
        setNumberOfRuns();
        outputTree.expandPath(new TreePath(e.getNewParent().getPath()));
    }

    //===============================================================================
    // GUI methods

    //-------------------------------------------------------------------------------
    private void layoutGUI() {
        leftTop = FormsUtils.build("p ' p:g", "[DialogBorder]00|" + "11||" + "23||" + "44||" + "5_|" + "6_|" + "7_",
                text1, text2, runsLabel, runsField, new Separator("Define parameter space"), constDef, listDef,
                incrDef).getPanel();

        constDefPanel = FormsUtils.build("p ~ p:g p", "[DialogBorder]012 p", "Constant value: ",
                CellConstraints.TOP, constDefField, browseFileButton).getPanel();

        enumConstPanel = FormsUtils
                .build("p ~ p:g", "[DialogBorder]01 p", "Constant value: ", CellConstraints.TOP, enumComboBox)
                .getPanel();

        listDefPanel = FormsUtils.build("p ~ p:g", "[DialogBorder]01|" + "_1 f:p:g||" + "_2 p", "Value list: ",
                listDefScr, "(Separate values with spaces!)").getPanel();

        incrDefPanel = FormsUtils.build("p ~ p:g", "[DialogBorder]01||" + "23||" + "45", "Start value: ",
                incrStartValueField, "End value: ", incrEndValueField, "Step: ", incrStepField).getPanel();

        enumListPanel = FormsUtils.build("p ~ p", "[DialogBorder]01||" + "23||", leftEnumValuePane,
                RightEnumValuePane, addEnumButton, removeEnumButton).getPanel();

        constDefPanel.setName("CONST");
        listDefPanel.setName("LIST");
        incrDefPanel.setName("INCREMENT");
        enumListPanel.setName("ENUMLIST");
        enumConstPanel.setName("ENUMCONST");
        leftMiddle.add(constDefPanel, constDefPanel.getName());
        leftMiddle.add(listDefPanel, listDefPanel.getName());
        leftMiddle.add(incrDefPanel, incrDefPanel.getName());
        leftMiddle.add(enumListPanel, enumListPanel.getName());
        leftMiddle.add(enumConstPanel, enumConstPanel.getName());

        leftBottom = FormsUtils.build("p:g p ~ p ~ p:g", "[DialogBorder]_01_ p", modifyButton, cancelButton)
                .getPanel();

        // left 
        leftFirst.add(leftTop, BorderLayout.NORTH);
        leftFirst.add(leftMiddle, BorderLayout.CENTER);
        leftFirst.add(leftBottom, BorderLayout.SOUTH);

        leftSecond.add(newParameterButton);

        left = FormsUtils.build("p", "0 f:p:g||" + "1 p", leftFirst, leftSecond).getPanel();

        //      right = FormsUtils.build("p:g ~ p ~",
        //                         "01|" +
        //                         "0_ f:p:g||" +
        //                         "22 p",
        //                         treeScr,FormsUtils.buttonStack(moveUpButton,moveDownButton,editButton).getPanel(),
        //                         numberOfRunsLabel).getPanel();

        right = FormsUtils.build("p:g ~ p ~", "00||" + "12|" + "1_ f:p:g||", numberOfRunsLabel, treeScr,
                FormsUtils.buttonStack(moveUpButton, moveDownButton, editButton).getPanel()).getPanel();

        content = FormsUtils.build("p p:g", "01 f:p:g", left, right).getPanel();

        this.setLayout(new BorderLayout());
        final JScrollPane sp = new JScrollPane(content);
        this.add(sp, BorderLayout.CENTER);

        outputTree.setName("tree_wizard_params");
        runsField.setName("fld_wizard_params_runs");
        constDef.setName("rbtn_wizard_params_const");
        listDef.setName("rbtn_wizard_params_list");
        incrDef.setName("rbtn_wizard_params_incr");
        modifyButton.setName("btn_wizard_params_modify");
        cancelButton.setName("btn_wizard_params_cancel");
        incrStartValueField.setName("fld_wizard_params_incrstart");
        incrEndValueField.setName("fld_wizard_params_incrend");
        incrStepField.setName("fld_wizard_params_incrstep");
        constDefField.setName("fld_wizard_params_constval");
        moveUpButton.setName("btn_wizard_params_moveup");
        moveDownButton.setName("btn_wizard_params_movedown");
        editButton.setName("btn_wizard_params_edit");
        listDefArea.setName("fld_wizard_params_paramlist");

    }

    //------------------------------------------------------------------------------
    private void initialize() {
        leftFirst.setBorder(BorderFactory.createTitledBorder("Parameter settings"));

        runsField.setActionCommand("RUNS_FIELD");
        runsField.addFocusListener(this);
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL)
            runsField.setEnabled(true);

        GUIUtils.createButtonGroup(constDef, listDef, incrDef);
        constDef.setSelected(true);
        constDef.setActionCommand("CONST");
        listDef.setActionCommand("LIST");
        incrDef.setActionCommand("INCREMENT");

        constDefField.setActionCommand("CONST_FIELD");
        incrStartValueField.setActionCommand("START_FIELD");
        incrEndValueField.setActionCommand("END_FIELD");
        incrStepField.setActionCommand("STEP_FIELD");
        browseFileButton.setActionCommand("BROWSE");

        modifyButton.setActionCommand("MODIFY");
        cancelButton.setActionCommand("CANCEL");
        addEnumButton.setActionCommand("ADD");
        removeEnumButton.setActionCommand("REMOVE");

        newParameterButton.setActionCommand("NEW_PARAMETER");
        newParameterButtonCopy.setActionCommand("NEW_PARAMETER");

        listDefArea.setLineWrap(true);
        listDefArea.setWrapStyleWord(true);
        listDefScr.setPreferredSize(new Dimension(100, 200));

        outputTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        outputTree.setCellRenderer(new ParameterTreeRenderer());
        outputTree.addTreeSelectionListener(this);
        outputTree.addDropSuccessfulListener(this);
        outputTree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (editedNode == null || modify()) {
                    Point loc = e.getPoint();
                    TreePath path = outputTree.getPathForLocation(loc.x, loc.y);
                    DefaultMutableTreeNode actNode = null;
                    if (path != null)
                        actNode = (DefaultMutableTreeNode) path.getLastPathComponent();
                    if (root.equals(actNode)) {
                        if (cancelButton.isEnabled())
                            cancelButton.doClick();
                        return;
                    }
                    if (actNode != null && SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2)
                        hybridAction(null, editAction);
                }
            }
        });

        right.setBorder(BorderFactory.createTitledBorder("Output structure"));
        treeScr.setPreferredSize(new Dimension(300, 400));
        browseFileButton.setVisible(false);

        initializeContextMenu();

        GUIUtils.addActionListener(this, modifyButton, cancelButton, constDef, listDef, incrDef, runsField,
                constDefField, incrStartValueField, incrEndValueField, incrStepField, newParameterButton,
                newParameterButtonCopy, browseFileButton, addEnumButton, removeEnumButton);
    }

    //------------------------------------------------------------------------------
    /** Initializes the context menu of the parameters tree. */
    private void initializeContextMenu() {
        JPopupMenu context = outputTree.getContextMenu();
        context.setName("cmenu_wizard_parameters_treecmenu");
        context.addSeparator();
        context.add(editAction);
        context.add(moveUpAction);
        context.add(moveDownAction);

        context.getComponent(3).setName("btn_wizard_params_cmenuedit");
        context.getComponent(4).setName("btn_wizard_params_cmenumoveup");
        context.getComponent(5).setName("btn_wizard_params_cmenumovedown");

        editAction.setEnabled(false);
        moveUpAction.setEnabled(false);
        moveDownAction.setEnabled(false);
    }

    //------------------------------------------------------------------------------
    /** Enables/disables the parameter editing components of the page according to
     *  the value of <code>enabled</code>.
     */
    private void enableDisableSettings(boolean enabled) {
        runsField.setEnabled(
                enabled || PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL);
        constDef.setEnabled(enabled);
        listDef.setEnabled(enabled);
        incrDef.setEnabled(enabled);
        constDefField.setEnabled(enabled);
        listDefArea.setEnabled(enabled);
        incrStartValueField.setEnabled(enabled);
        incrEndValueField.setEnabled(enabled);
        incrStepField.setEnabled(enabled);
        cancelButton.setEnabled(enabled);
        enumComboBox.setEnabled(enabled);
        addEnumButton.setEnabled(enabled);
        removeEnumButton.setEnabled(enabled);
        newParameterButton
                .setEnabled(PlatformSettings.getGUIControllerForPlatform().isNewParametersEnabled() && !enabled);
    }

    //------------------------------------------------------------------------------
    /** Changes the text on the left top corner of the page. The text can be the initial
     *  commentary text ("Select a parameter from the tree to modify its settings") or
     *  the name and type of the edited parameter.
     * @param name name of the edited parameter (null if there is no editing parameter)
     * @param type name of type of the edited parameter
     */
    private void changeText(String name, String type) {
        if (name == null) {
            text1.setText(orderPart1);
            text2.setText(orderPart2);
        } else {
            text1.setText("<html><b>" + name + "</b>: " + type + "</html>");
            text2.setText(" ");
        }
    }

    //------------------------------------------------------------------------------
    /** Resets the parameter editing related components. */
    private void resetSettings() {
        changeText(null, null);
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL)
            runsField.setText("");
        constDefField.setText("");
        listDefArea.setText("");
        incrStartValueField.setText("");
        incrEndValueField.setText("");
        incrStepField.setText("");
        leftEnumValueModel.clear();
        rightEnumValueModel.clear();
        enumComboBoxModel.removeAllElements();
    }

    //==============================================================================
    // private methods

    //------------------------------------------------------------------------------
    /** Deletes all parameters from the parameter tree. */
    private void clearTree() {
        root = new DefaultMutableTreeNode("Parameter file");
        outputTree.setModel(new DefaultTreeModel(root));
    }

    //------------------------------------------------------------------------------
    /** Creates the list of information objects of parameters. */
    @SuppressWarnings("unchecked")
    private List<ParameterInfo> createParameters() {
        List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> paramList = null;
        try {
            paramList = owner.getModelInformation().getParameters();
        } catch (ModelInformationException e) {
            Utilities.userAlert(owner, "Identification of parameters is failed:", Util.getLocalizedMessage(e));
            modelInformationException = true;
            owner.enableDisableButtons();
            owner.setModelState(ParameterSweepWizard.ERROR);
            e.printStackTrace(ParameterSweepWizard.getLogStream());
            return null;
        }
        originalInitParamResult = new String[paramList.size()];
        for (int i = 0; i < paramList.size(); ++i)
            originalInitParamResult[i] = paramList.get(i).getName();
        List<ParameterInfo> info = new ArrayList<ParameterInfo>();
        for (ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?> parameter : paramList) {
            ParameterInfo pi = InfoConverter.parameterInfo2ParameterInfo(parameter);
            if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL)
                pi.setRuns(1);
            pi.setDefinitionType(ParameterInfo.CONST_DEF);
            pi.setValue(parameter.getDefaultValue());
            info.add(pi);

        }
        if (newParameters != null) {
            initParamResult = new String[originalInitParamResult.length + newParameters.size()];
            for (int i = 0; i < originalInitParamResult.length; ++i)
                initParamResult[i] = originalInitParamResult[i];
            for (int i = 0; i < newParameters.size(); ++i) {
                String name = newParameters.get(i).getName();
                initParamResult[originalInitParamResult.length + i] = name;
                newParameters.get(i).setName(Util.capitalize(name));
            }
            info.addAll(newParameters);
        } else
            initParamResult = originalInitParamResult;
        Collections.sort(info);
        return info;
    }

    //------------------------------------------------------------------------------
    /** Builds the parameter tree from the <code>parameters</code> list. */
    private void createDefaultTree() {
        if (parameters == null)
            return;
        for (ParameterInfo pi : parameters)
            root.add(new DefaultMutableTreeNode(pi));
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL)
            runsField.setText("1");
        outputTree.expandRow(0);
    }

    //------------------------------------------------------------------------------
    /** Edits the information object <code>info</code> so this method fills the appropriate
     *  components with the informations of <code>info</code>.
     */
    private void edit(ParameterInfo info) {
        changeText(info.getName(), info.getType());
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL)
            runsField.setText(String.valueOf(info.getRuns()));
        String view = null;

        if (info instanceof MasonChooserParameterInfo) {
            leftEnumValueModel.clear();
            enumComboBoxModel.removeAllElements();
            for (String s : ((MasonChooserParameterInfo) info).getValidStrings()) {
                enumComboBoxModel.addElement(s);
                leftEnumValueModel.addElement(s);
            }
        }
        if (info.isEnum()) {
            leftEnumValueModel.clear();
            enumComboBoxModel.removeAllElements();
            Object[] elements = info.getJavaType().getEnumConstants();
            for (Object element : elements) {
                enumComboBoxModel.addElement(((Enum) element).name());
                leftEnumValueModel.addElement(((Enum) element).name());
            }
        }

        switch (info.getDefinitionType()) {
        case ParameterInfo.CONST_DEF:
            if (info instanceof MasonChooserParameterInfo || info.isEnum())
                view = "ENUMCONST";
            else
                view = "CONST";
            constDef.setSelected(true);
            constDefField.setText(info.valuesToString());
            break;
        case ParameterInfo.LIST_DEF:
            if (info instanceof MasonChooserParameterInfo || info.isEnum())
                view = "ENUMLIST";
            else
                view = "LIST";
            listDef.setSelected(true);
            listDefArea.setText(info.valuesToString());
            break;
        case ParameterInfo.INCR_DEF:
            view = "INCREMENT";
            incrDef.setSelected(true);
            incrStartValueField.setText(info.startToString());
            incrEndValueField.setText(info.endToString());
            incrStepField.setText(info.stepToString());
        }
        CardLayout cl = (CardLayout) leftMiddle.getLayout();
        cl.show(leftMiddle, view);
        browseFileButton.setEnabled(false);
        enableDisableSettings(true);
        if (!info.isNumeric())
            incrDef.setEnabled(false);
        modifyButton.setEnabled(true);
        if (info.isFile()) {
            listDef.setEnabled(false);
            browseFileButton.setVisible(true);
        }
    }

    //------------------------------------------------------------------------------
    /** Checks the content of the editing components. 
     * @param node the node that belongs to the edited parameter
     * @return the error messages in an array (or null if there is no error)
     */
    private String[] checkInput(DefaultMutableTreeNode node) {
        ArrayList<String> errors = new ArrayList<String>();
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL) {
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
            boolean allowEmptyRun = (parent.equals(root) && !parent.getFirstChild().equals(node))
                    || constDef.isSelected();
            if (runsField.getText().trim().equals("") && !allowEmptyRun)
                errors.add("'Runs' cannot be empty.");
            else if (!runsField.getText().trim().equals("")) {
                try {
                    long i = new Long(runsField.getText().trim()).longValue();
                    if (i <= 0)
                        throw new NumberFormatException();
                } catch (NumberFormatException e) {
                    errors.add("'Runs' must be a positive integer.");
                }
            }
        }
        ParameterInfo info = (ParameterInfo) node.getUserObject();
        if (constDef.isSelected()) {
            if (!(info instanceof MasonChooserParameterInfo || info.isEnum())) {
                if (constDefField.getText().trim().equals(""))
                    errors.add("'Constant value' cannot be empty.");
                else {
                    boolean valid = ParameterInfo.isValid(constDefField.getText().trim(), info.getType());
                    if (!valid)
                        errors.add("'Constant value' must be a valid " + getTypeText(info.getType()));
                    errors.addAll(PlatformSettings.additionalParameterCheck(info,
                            new String[] { constDefField.getText().trim() }, ParameterInfo.CONST_DEF));
                }
            }
        } else if (listDef.isSelected()) {
            if (info instanceof MasonChooserParameterInfo || info.isEnum()) {
                if (rightEnumValueModel.isEmpty()) {
                    errors.add("'List of values' cannot be empty." + getTypeText(info.getType()));
                }
            } else {
                String text = listDefArea.getText().trim();
                if (text.equals(""))
                    errors.add("'List of values' cannot be empty.");
                else {
                    text = text.replaceAll("[\\s]+", " ");
                    String[] elements = text.split(" ");
                    boolean goodList = true;
                    for (String element : elements)
                        goodList = goodList && ParameterInfo.isValid(element.trim(), info.getType());
                    if (!goodList)
                        errors.add("All elements of the list must be a valid " + getTypeText(info.getType()));
                    else {
                        List<String> previous = new ArrayList<String>(elements.length);
                        for (String element : elements) {
                            if (previous.contains(element)) {
                                goodList = false;
                                break;
                            }
                            previous.add(element);
                        }
                        if (!goodList) {
                            int result = Utilities.askUser(owner, false, "Warning",
                                    "The list contains repetitive element(s).\nAre you sure?");
                            if (result == 0 && errors.size() == 0)
                                return new String[0];
                        }
                    }
                    errors.addAll(
                            PlatformSettings.additionalParameterCheck(info, elements, ParameterInfo.LIST_DEF));
                }
            }
        } else {
            boolean s = false, e = false, st = false;
            if (incrStartValueField.getText().trim().equals("")) {
                errors.add("'Start value' cannot be empty.");
                s = true;
            } else {
                boolean valid = ParameterInfo.isValid(incrStartValueField.getText().trim(), info.getType());
                if (!valid)
                    errors.add("'Start value' must be a valid " + getTypeText(info.getType()));
            }
            if (incrEndValueField.getText().trim().equals("")) {
                errors.add("'End value' cannot be empty.");
                e = true;
            } else {
                boolean valid = ParameterInfo.isValid(incrEndValueField.getText().trim(), info.getType());
                if (!valid)
                    errors.add("'End value' must be a valid " + getTypeText(info.getType()));
            }
            if (incrStepField.getText().trim().equals("")) {
                errors.add("'Step' cannot be empty.");
                st = true;
            } else {
                double d = Double.valueOf(incrStepField.getText().trim());
                if (d == 0)
                    errors.add("'Step' cannot be zero.");
                else {
                    boolean valid = ParameterInfo.isValid(incrStepField.getText().trim(), info.getType());
                    if (!valid)
                        errors.add("'Step' must be a valid " + getTypeText(info.getType()));
                }
            }
            if (!(s || e || st))
                errors.addAll(PlatformSettings.additionalParameterCheck(
                        info, new String[] { incrStartValueField.getText().trim(),
                                incrEndValueField.getText().trim(), incrStepField.getText().trim() },
                        ParameterInfo.INCR_DEF));
        }
        return errors.size() == 0 ? null : errors.toArray(new String[0]);
    }

    //------------------------------------------------------------------------------
    /** Returns the appropriate error message part according to the value of <code>type</code>. */
    private String getTypeText(String type) {
        if ("int".equals(type) || "Integer".equals(type))
            return "integer value.";
        if ("float".equals(type) || "Float".equals(type) || "double".equals(type) || "Double".equals(type))
            return "real value.";
        if ("boolean".equals(type) || "Boolean".equals(type))
            return "boolean value (\"true\" or \"false\").";
        if ("String".equals(type))
            return "string that not contains any white space.";
        return type + ".";
    }

    //----------------------------------------------------------------------------------------------------
    private boolean modify() {
        String[] errors = checkInput(editedNode);
        if (errors != null && errors.length != 0) {
            Utilities.userAlert(this, (Object) errors);
            return false;
        } else {
            modifyParameterInfo(editedNode);
            resetSettings();
            enableDisableSettings(false);
            modifyButton.setEnabled(false);
            outputTree.repaint();
            TreePath path = new TreePath(editedNode.getPath());
            outputTree.setSelectionPath(path);
            fireTreeStructureChanged(path);
            editedNode = null;
            setNumberOfRuns();
            return true;
        }
    }

    //------------------------------------------------------------------------------
    // Pre-condition : all input are valid
    /** Modifies the information object that belongs to <code>node</code> from the
     *  contents of the editing components of the page.<br>
     *  Pre-condition: all input values are valid.
     */
    private void modifyParameterInfo(DefaultMutableTreeNode node) {
        DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
        ParameterInfo info = (ParameterInfo) node.getUserObject();
        info.clear();
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.LOCAL) {
            if (runsField.getText().trim().equals("")) {
                if (constDef.isSelected())
                    info.setRuns(1);
                else {
                    ParameterInfo prev = (ParameterInfo) ((DefaultMutableTreeNode) parent.getChildBefore(node))
                            .getUserObject();
                    info.setRuns(prev.getRuns());
                }
            } else {
                long i = Long.parseLong(runsField.getText().trim());
                info.setRuns(i);
            }
        }

        int defType = ParameterInfo.CONST_DEF;
        if (listDef.isSelected())
            defType = ParameterInfo.LIST_DEF;
        else if (incrDef.isSelected())
            defType = ParameterInfo.INCR_DEF;
        info.setDefinitionType(defType);
        switch (defType) {
        case ParameterInfo.CONST_DEF:
            if (info instanceof MasonChooserParameterInfo || info.isEnum())
                info.setValue(enumComboBox.getSelectedIndex());
            else
                info.setValue(ParameterInfo.getValue(constDefField.getText().trim(), info.getType()));
            break;
        case ParameterInfo.LIST_DEF:
            if (info instanceof MasonChooserParameterInfo || info.isEnum()) {
                List<Object> values = new ArrayList<Object>();
                for (int i = 0; i < rightEnumValueModel.size(); i++) {
                    values.add(leftEnumValueModel.indexOf(rightEnumValueModel.elementAt(i)));
                }
                info.setValues(values);
            } else {
                String text = listDefArea.getText().trim();
                text = text.replaceAll("[\\s]+", " ");
                String[] elements = text.split(" ");
                List<Object> list = new ArrayList<Object>(elements.length);
                for (String element : elements)
                    list.add(ParameterInfo.getValue(element, info.getType()));
                info.setValues(list);
            }
            break;
        case ParameterInfo.INCR_DEF:
            info.setStartValue(
                    (Number) ParameterInfo.getValue(incrStartValueField.getText().trim(), info.getType()));
            info.setEndValue((Number) ParameterInfo.getValue(incrEndValueField.getText().trim(), info.getType()));
            info.setStep((Number) ParameterInfo.getValue(incrStepField.getText().trim(), info.getType()));
            break;
        }
    }

    //------------------------------------------------------------------------------
    /** Notifies all listeners of the parameters tree that the structure of the tree is
     *  changed.
     */
    private void fireTreeStructureChanged(TreePath path) {
        // Guaranteed to return a non-null array
        Object[] listeners = ((DefaultTreeModel) outputTree.getModel()).getListeners(TreeModelListener.class);
        TreeModelEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 1; i >= 0; i--) {
            // Lazily create the event:
            if (e == null)
                e = new TreeModelEvent(this, path);
            ((TreeModelListener) listeners[i]).treeStructureChanged(e);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void initializePageForPlatform() {
        IGUIController controller = PlatformSettings.getGUIControllerForPlatform();
        newParameterButton.setEnabled(controller.isNewParametersEnabled());
        newParameterButtonCopy.setEnabled(controller.isNewParametersEnabled());
        switch (controller.getRunOption()) {
        case NONE:
            runsLabel.setVisible(false);
            runsField.setVisible(false);
            break;
        case GLOBAL:
            runsLabel.setText("Runs (global): ");
        }
    }

    //----------------------------------------------------------------------------------------------------
    private long parseGlobalRuns() {
        long runs = 1;
        final String runsStr = runsField.getText().trim();
        if (runsStr != null && runsStr.length() > 0) {
            try {
                runs = Long.parseLong(runsStr);
            } catch (NumberFormatException e) {
            }
        }
        return runs;
    }

    //----------------------------------------------------------------------------------------------------
    private void setGlobalRunsField() {
        if (PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(0);
            if (node != null) {
                ParameterInfo pi = (ParameterInfo) node.getUserObject();
                if (pi != null)
                    runsField.setText(String.valueOf(pi.getRuns()));
            }
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void setNumberOfRuns() {
        final long globalRuns = PlatformSettings.getGUIControllerForPlatform().getRunOption() == RunOption.GLOBAL
                ? parseGlobalRuns()
                : -1;
        final long nrRuns = Utilities.calculateNumberOfRuns(root, globalRuns);
        String text = "<html>&nbsp;A total of " + nrRuns + " run" + (nrRuns > 1 ? "s" : "") + ".";

        if (needTreeFormatWarning())
            text += "<font color=\"#FF0000\"> (Warning: Multiple non-constant branches)</font>";
        text += "</html>";
        numberOfRunsLabel.setText(text);
    }

    //==============================================================================
    // nested classes

    //----------------------------------------------------------------------------------------------------
    /** This class renders the parameters tree. */
    @SuppressWarnings("serial")
    private class ParameterTreeRenderer extends DnDTreeCellRenderer {

        //====================================================================================================
        // members

        private ImageIcon parameterIcon = ExpandedEditor.getIcon("type_parameter.png");

        //====================================================================================================
        // methods

        //----------------------------------------------------------------------------------------------------
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
                boolean leaf, int row, boolean focus) {
            Component com = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, focus);
            Icon icon = ((DefaultMutableTreeNode) value).equals(root) ? leafIcon : parameterIcon;
            if (icon != null)
                ((JLabel) com).setIcon(icon);
            tree.setToolTipText(value.toString());
            ((JLabel) com).setToolTipText(value.toString());
            return com;
        }

    }

    //----------------------------------------------------------------------------------------------------
    private class IntelliContext extends HashMap<Object, Object> implements IIntelliContext {
        {
            put("scriptSupport", owner.getRecordersPage().getScriptSupport());
        }
        private static final long serialVersionUID = -7383965550748377433L;

        public List<ParameterInfo> getParameters() {
            return parameters;
        }

        public DefaultMutableTreeNode getParameterTreeRootNode() {
            return root;
        }

        public JButton getNewParametersButton() {
            return Page_Parameters.this.getNewParametersButton();
        }

        public File getPluginResourcesDirectory() {
            return new File(System.getProperty("user.dir") + "/resources/Plugins");
        }
    }
}