ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.GASearchPanel.java Source code

Java tutorial

Introduction

Here is the source code for ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.GASearchPanel.java

Source

/*******************************************************************************
 * Copyright (C) 2006-2014 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.intellisweepPlugin.jgap;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
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 org.jdesktop.swingx.JXLabel;

import ai.aitia.meme.Logger;
import ai.aitia.meme.paramsweep.ParameterSweepWizard;
import ai.aitia.meme.paramsweep.batch.output.RecordableInfo;
import ai.aitia.meme.paramsweep.gui.component.CheckList;
import ai.aitia.meme.paramsweep.gui.component.CheckListModel;
import ai.aitia.meme.paramsweep.gui.component.DefaultJButton;
import ai.aitia.meme.paramsweep.gui.component.ListAsATree;
import ai.aitia.meme.paramsweep.gui.info.MasonChooserParameterInfo;
import ai.aitia.meme.paramsweep.gui.info.ParameterInfo;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.GASearchPanelModel.FitnessFunctionDirection;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.GASearchPanelModel.ModelListener;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.configurator.IGAConfigurator;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.configurator.IGAOperatorConfigurator;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.configurator.IGASelectorConfigurator;
import ai.aitia.meme.paramsweep.intellisweepPlugin.jgap.gene.ParameterOrGene;
import ai.aitia.meme.paramsweep.intellisweepPlugin.utils.ga.GeneInfo;
import ai.aitia.meme.paramsweep.internal.platform.PlatformSettings;
import ai.aitia.meme.paramsweep.utils.Utilities;
import ai.aitia.meme.utils.FormsUtils;
import ai.aitia.meme.utils.FormsUtils.Separator;
import ai.aitia.meme.utils.GUIUtils;
import ai.aitia.meme.utils.Utils;

import com.jgoodies.forms.layout.CellConstraints;

/**
 * @author Tams Mhr
 * @author Rajmund Bocsi
 *
 */
public class GASearchPanel extends JPanel {

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

    private static final long serialVersionUID = 7957280032992002080L;

    private static final int ICON_WIDTH_AND_HEIGHT = 25;

    private static final ImageIcon ENUM_ADD_ICON_DIS = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_silver_right.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));
    private static final ImageIcon ENUM_ADD_ICON = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_green_right.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));
    private static final ImageIcon ENUM_ADD_ICON_RO = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_red_right.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));

    private static final ImageIcon ENUM_REMOVE_ICON_DIS = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_silver_left.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));
    private static final ImageIcon ENUM_REMOVE_ICON = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_green_left.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));
    private static final ImageIcon ENUM_REMOVE_ICON_RO = new ImageIcon(
            new ImageIcon(ParameterSweepWizard.class.getResource("gui/icons/arrow_button_metal_red_left.png"))
                    .getImage()
                    .getScaledInstance(ICON_WIDTH_AND_HEIGHT, ICON_WIDTH_AND_HEIGHT, Image.SCALE_SMOOTH));

    private static final String GENE_SETTINGS_INT_RANGE_VALUE_PANEL = "int_range";
    private static final String GENE_SETTINGS_DOUBLE_RANGE_VALUE_PANEL = "double_range";
    private static final String GENE_SETTINGS_LIST_VALUE_PANEL = "list";
    private static final String GENE_SETTINGS_ENUM_LIST_PANEL = "enum_list";
    private static final String PARAM_SETTINGS_CONSTANT_VALUE_PANEL = "constant";
    private static final String PARAM_SETTINGS_ENUM_VALUE_PANEL = "enum";
    private static final String PARAM_SETTINGS_FILE_VALUE_PANEL = "file";

    private static final String OPERATOR_SETTINGS_PANEL_DEFAULT_PANEL = "DEFAULT";
    private static final String OPERATOR_SETTINGS_PANEL_TITLE_POSTFIX = "Operator settings";

    private static final NumberFormat numberFormatter = NumberFormat.getInstance(Locale.US);

    static { // print double numbers rounded to 2 decimal digits using US format
        numberFormatter.setMaximumFractionDigits(2);
        numberFormatter.setMinimumFractionDigits(0);
        numberFormatter.setGroupingUsed(false);
    }

    private JSpinner populationSizeField;
    private JTextField populationRandomSeedField;
    private JRadioButton numberOfGenerationsRadioButton;
    private JSpinner numberOfGenerationsField;
    private JRadioButton fitnessLimitRadioButton;
    private JTextField fitnessLimitField;
    private JRadioButton fitnessMinimizeRadioButton;
    private JRadioButton fitnessMaximizeRadioButton;
    private JComboBox<RecordableInfo> fitnessFunctionList;
    private JTree geneTree;
    private JLabel numberLabel;
    protected Popup errorPopup;
    private JTextField constantField;
    private JTextField intMinField;
    private JTextField intMaxField;
    private JTextField doubleMinField;
    private JTextField doubleMaxField;
    private JTextArea valuesArea;
    private JComboBox<Object> enumDefBox;
    private JList<Object> leftEnumValueList;
    private JList<Object> rightEnumValueList;
    private JButton addEnumButton;
    private JButton removeEnumButton;
    private JTextField fileTextField;
    private JButton fileBrowseButton;

    private JButton localNewParametersButton;
    private JButton remoteNewParametersButton;

    private JRadioButton constantRButton;
    private JRadioButton geneRButton;
    private JRadioButton doubleGeneValueRangeRButton;
    private JRadioButton intGeneValueRangeRButton;
    private JRadioButton listGeneValueRButton;
    private JPanel geneSettingsValuePanel;

    private JButton modifyButton;
    private JButton cancelButton;

    private JScrollPane mainScrPane;
    private JPanel operatorSettingsPanel;
    private CheckList selectorList;
    private CheckList operatorList;

    private DefaultMutableTreeNode editedNode;

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

    //----------------------------------------------------------------------------------------------------
    public GASearchPanel(final GASearchPanelModel model, final JButton remoteNewParametersButton) {
        this.remoteNewParametersButton = remoteNewParametersButton;
        initSearchPanel(model);
    }

    //----------------------------------------------------------------------------------------------------
    public void reset(final GASearchPanelModel model) {
        populationSizeField.setValue(model.getPopulationSize());
        populationRandomSeedField.setText(String.valueOf(model.getPopulationRandomSeed()));

        // create the stopping conditions panel
        numberOfGenerationsRadioButton.setSelected(true);
        numberOfGenerationsField.setValue(model.getNumberOfGenerations());
        fitnessLimitField.setText(String.valueOf(model.getFitnessLimitCriterion()));

        if (model.getNumberOfGenerations() < 0) {
            fitnessLimitRadioButton.setSelected(true);
            numberOfGenerationsField.setEnabled(false);
        } else {
            fitnessLimitField.setEnabled(false);
            numberOfGenerationsRadioButton.setSelected(true);
        }

        if (model.getFitnessFunctionDirection() == FitnessFunctionDirection.MINIMIZE)
            fitnessMinimizeRadioButton.setSelected(true);
        else
            fitnessMaximizeRadioButton.setSelected(true);
        //      fitnessFunctionList.setSelectedItem(model.getSelectedFitnessFunction()); // set fitness function later

        final CardLayout settingslayout = (CardLayout) operatorSettingsPanel.getLayout();
        settingslayout.show(operatorSettingsPanel, OPERATOR_SETTINGS_PANEL_DEFAULT_PANEL);
        ((TitledBorder) operatorSettingsPanel.getBorder()).setTitle(OPERATOR_SETTINGS_PANEL_TITLE_POSTFIX);

        final List<IGASelectorConfigurator> selectionOperators = model.getSelectionOperators();
        final List<IGASelectorConfigurator> selectedSelectionOperators = model.getSelectedSelectionOperators();

        int i = 0;
        for (final IGASelectorConfigurator selectionOperator : selectionOperators) {
            selectorList.setChecked(i, selectedSelectionOperators.contains(selectionOperator));
            ++i;
        }
        selectorList.clearSelection();

        final List<IGAOperatorConfigurator> geneticOperators = model.getGeneticOperators();
        final List<IGAOperatorConfigurator> selectedGeneticOperators = model.getSelectedGeneticOperators();

        i = 0;
        for (final IGAOperatorConfigurator operator : geneticOperators) {
            operatorList.setChecked(i, selectedGeneticOperators.contains(operator));
            ++i;
        }
        operatorList.clearSelection();

        numberLabel.setText("<html><b>Number of genes:</b> 0</html>");

        for (int j = 0; j < geneTree.getRowCount(); ++j)
            geneTree.expandRow(j);

        resetSettings();
        enableDisableSettings(false);
        localNewParametersButton
                .setVisible(PlatformSettings.getGUIControllerForPlatform().isNewParametersEnabled());
        updateNumberOfGenes();
    }

    //====================================================================================================
    // assistant methods

    //----------------------------------------------------------------------------------------------------
    private void initSearchPanel(final GASearchPanelModel model) {
        model.addModelListener(new ModelListener() {

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

            //----------------------------------------------------------------------------------------------------
            public void fitnessFunctionAdded() {
                fitnessFunctionList.removeAllItems();
                final List<RecordableInfo> list = model.getFitnessFunctions();
                for (final RecordableInfo fitnessFunction : list) {
                    fitnessFunctionList.addItem(fitnessFunction);
                }
            }

            //----------------------------------------------------------------------------------------------------
            public void fitnessFunctionsRemoved() {
                fitnessFunctionList.removeAllItems();
            }

            //----------------------------------------------------------------------------------------------------
            public void fitnessFunctionSelected(final RecordableInfo selectedFunction) {
                fitnessFunctionList.setSelectedItem(selectedFunction);
            }

            //----------------------------------------------------------------------------------------------------
            public void parameterAdded() {
                final DefaultTreeModel treeModel = model.getChromosomeTree();
                final DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
                geneTree.expandPath(new TreePath(treeModel.getPathToRoot(root)));
            }

            //----------------------------------------------------------------------------------------------------
            public void parametersRemoved() {
                parameterAdded(); // :)
            }
        });

        // create the population parameters panel
        populationSizeField = new JSpinner(
                new SpinnerNumberModel(model.getPopulationSize(), 2, Integer.MAX_VALUE, 1));
        populationSizeField.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent e) {
                model.setPopulationSize((Integer) ((JSpinner) e.getSource()).getValue());
            }
        });

        populationRandomSeedField = new JTextField(String.valueOf(model.getPopulationRandomSeed()));
        populationRandomSeedField.setInputVerifier(new InputVerifier() {
            @Override
            public boolean verify(final JComponent input) {
                if (errorPopup != null) {
                    errorPopup.hide();
                    errorPopup = null;
                }

                try {
                    final int value = Integer.parseInt(populationRandomSeedField.getText());
                    model.setPopulationRandomSeed(value);
                    return true;
                } catch (final NumberFormatException e) {
                    final PopupFactory popupFactory = PopupFactory.getSharedInstance();
                    final Point locationOnScreen = populationRandomSeedField.getLocationOnScreen();
                    final JLabel message = new JLabel("Please specify an integer number!");
                    message.setBorder(new LineBorder(Color.RED, 2, true));
                    errorPopup = popupFactory.getPopup(populationRandomSeedField, message, locationOnScreen.x - 10,
                            locationOnScreen.y - 30);
                    errorPopup.show();

                    return false;
                }
            }
        });

        final JPanel populationPanel = FormsUtils.build("p ~ f:p:g", "01 ||" + "23", "Size", populationSizeField,
                "Random seed", populationRandomSeedField).getPanel();
        populationPanel.setBorder(
                BorderFactory.createTitledBorder(null, "Population", TitledBorder.LEADING, TitledBorder.BELOW_TOP));

        // create the stopping conditions panel
        numberOfGenerationsRadioButton = new JRadioButton("Number of generations");
        numberOfGenerationsField = new JSpinner(
                new SpinnerNumberModel(model.getNumberOfGenerations(), 1, Integer.MAX_VALUE, 1));
        numberOfGenerationsField.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent e) {
                model.setNumberOfGenerations((Integer) ((JSpinner) e.getSource()).getValue());
            }
        });
        numberOfGenerationsRadioButton.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent e) {
                if (numberOfGenerationsRadioButton.isSelected()) {
                    numberOfGenerationsField.setEnabled(true);
                    model.setFixNumberOfGenerations(true);
                } else
                    numberOfGenerationsField.setEnabled(false);
            }
        });

        fitnessLimitRadioButton = new JRadioButton("Fitness limit");
        fitnessLimitField = new JTextField(String.valueOf(model.getFitnessLimitCriterion()));
        fitnessLimitField.setInputVerifier(new InputVerifier() {
            @Override
            public boolean verify(final JComponent input) {
                if (errorPopup != null) {
                    errorPopup.hide();
                    errorPopup = null;
                }

                try {
                    final double value = Double.parseDouble(fitnessLimitField.getText());
                    if (value < 0)
                        throw new NumberFormatException();
                    model.setFitnessLimitCriterion(value);
                    return true;
                } catch (final NumberFormatException e) {
                    final PopupFactory popupFactory = PopupFactory.getSharedInstance();
                    final Point locationOnScreen = fitnessLimitField.getLocationOnScreen();
                    final JLabel message = new JLabel(
                            "Please specify a non-negative (possibly floating point) number!");
                    message.setBorder(new LineBorder(Color.RED, 2, true));
                    errorPopup = popupFactory.getPopup(fitnessLimitField, message, locationOnScreen.x - 10,
                            locationOnScreen.y - 30);
                    errorPopup.show();

                    return false;
                }
            }
        });
        fitnessLimitRadioButton.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(final ChangeEvent e) {
                if (fitnessLimitRadioButton.isSelected()) {
                    fitnessLimitField.setEnabled(true);
                    model.setFixNumberOfGenerations(false);
                } else
                    fitnessLimitField.setEnabled(false);
            }
        });

        GUIUtils.createButtonGroup(numberOfGenerationsRadioButton, fitnessLimitRadioButton);

        if (model.getNumberOfGenerations() < 0) {
            fitnessLimitRadioButton.setSelected(true);
            numberOfGenerationsField.setEnabled(false);
            model.setFixNumberOfGenerations(false);
        } else {
            fitnessLimitField.setEnabled(false);
            numberOfGenerationsRadioButton.setSelected(true);
            model.setFixNumberOfGenerations(true);
        }

        final JPanel stoppingPanel = FormsUtils.build("p ~ f:p:g", "01 |" + "23", numberOfGenerationsRadioButton,
                numberOfGenerationsField, fitnessLimitRadioButton, fitnessLimitField).getPanel();
        stoppingPanel.setBorder(
                BorderFactory.createTitledBorder(null, "Stopping", TitledBorder.LEADING, TitledBorder.BELOW_TOP));

        // create the fitness function panel
        fitnessMinimizeRadioButton = new JRadioButton("Minimize");
        fitnessMaximizeRadioButton = new JRadioButton("Maximize");

        GUIUtils.createButtonGroup(fitnessMinimizeRadioButton, fitnessMaximizeRadioButton);
        GUIUtils.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (fitnessMinimizeRadioButton.isSelected())
                    model.setFitnessFunctionDirection(FitnessFunctionDirection.MINIMIZE);
                else if (fitnessMaximizeRadioButton.isSelected())
                    model.setFitnessFunctionDirection(FitnessFunctionDirection.MAXIMIZE);
            }
        }, fitnessMinimizeRadioButton, fitnessMaximizeRadioButton);

        if (model.getFitnessFunctionDirection() == FitnessFunctionDirection.MINIMIZE)
            fitnessMinimizeRadioButton.setSelected(true);
        else
            fitnessMaximizeRadioButton.setSelected(true);

        final JPanel fitnessButtonsPanel = new JPanel();
        fitnessButtonsPanel.add(fitnessMinimizeRadioButton);
        fitnessButtonsPanel.add(fitnessMaximizeRadioButton);

        fitnessFunctionList = new JComboBox<RecordableInfo>(
                model.getFitnessFunctions().toArray(new RecordableInfo[0]));
        fitnessFunctionList.setSelectedItem(model.getSelectedFitnessFunction());
        fitnessFunctionList.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (ItemEvent.SELECTED == e.getStateChange())
                    model.setSelectedFitnessFunction((RecordableInfo) e.getItem());
            }
        });

        final JXLabel fitnessMessage = new JXLabel(
                "Please specify a function that always returns with non-negative value!");
        fitnessMessage.setLineWrap(true);
        final JPanel fitnessPanel = FormsUtils.build("p ~ f:p:g", "00 ||" + "12 ||" + "33", fitnessButtonsPanel,
                "Fitness function", fitnessFunctionList, fitnessMessage).getPanel();
        fitnessPanel.setBorder(
                BorderFactory.createTitledBorder(null, "Fitness", TitledBorder.LEADING, TitledBorder.BELOW_TOP));

        operatorSettingsPanel = new JPanel(new CardLayout());
        operatorSettingsPanel.setBorder(BorderFactory.createTitledBorder(null,
                OPERATOR_SETTINGS_PANEL_TITLE_POSTFIX, TitledBorder.LEADING, TitledBorder.BELOW_TOP));
        operatorSettingsPanel.add(new JLabel(""), OPERATOR_SETTINGS_PANEL_DEFAULT_PANEL);

        final List<IGASelectorConfigurator> selectionOperators = model.getSelectionOperators();
        final List<IGASelectorConfigurator> selectedSelectionOperators = model.getSelectedSelectionOperators();
        final CheckListModel selectorListModel = new CheckListModel(selectionOperators);
        selectorList = new CheckList(selectorListModel);
        selectorList.setBorder(
                BorderFactory.createTitledBorder(null, "Selection", TitledBorder.LEADING, TitledBorder.BELOW_TOP));
        selectorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        int i = 0;
        for (final IGASelectorConfigurator selectionOperator : selectionOperators) {
            final JPanel settingspanel = selectionOperator.getSettingsPanel();
            operatorSettingsPanel.add(settingspanel, selectionOperator.getName());

            if (selectedSelectionOperators.contains(selectionOperator))
                selectorList.setChecked(i, true);

            ++i;
        }

        selectorList.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(final ListSelectionEvent e) {
                final IGASelectorConfigurator operator = (IGASelectorConfigurator) selectorList.getSelectedValue();
                showOperatorDetails(operatorSettingsPanel, operator);
            }
        });

        selectorListModel.addListDataListener(new ListDataListener() {

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

            //----------------------------------------------------------------------------------------------------
            @Override
            public void intervalRemoved(final ListDataEvent e) {
            }

            @Override
            public void intervalAdded(final ListDataEvent e) {
            }

            //----------------------------------------------------------------------------------------------------
            @Override
            public void contentsChanged(final ListDataEvent e) {
                final IGASelectorConfigurator operator = (IGASelectorConfigurator) selectorList.getSelectedValue();

                if (selectorList.getModel().getCheckedState(e.getIndex0()))
                    model.setSelectedSelectionOperator(operator);
                else
                    model.unsetSelectedSelectionOperator(operator);
            }
        });

        final List<IGAOperatorConfigurator> geneticOperators = model.getGeneticOperators();
        final List<IGAOperatorConfigurator> selectedGeneticOperators = model.getSelectedGeneticOperators();
        final CheckListModel operatorListModel = new CheckListModel(geneticOperators);
        operatorList = new CheckList(operatorListModel);
        operatorList.setBorder(BorderFactory.createTitledBorder(null, "Genetic operators", TitledBorder.LEADING,
                TitledBorder.BELOW_TOP));
        operatorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        i = 0;
        for (final IGAOperatorConfigurator operator : geneticOperators) {
            final JPanel settingsPanel = operator.getSettingsPanel();
            operatorSettingsPanel.add(settingsPanel, operator.getName());

            if (selectedGeneticOperators.contains(operator))
                operatorList.setChecked(i, true);

            ++i;
        }

        operatorList.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(final ListSelectionEvent e) {
                final IGAOperatorConfigurator operator = (IGAOperatorConfigurator) operatorList.getSelectedValue();
                showOperatorDetails(operatorSettingsPanel, operator);
            }
        });

        operatorListModel.addListDataListener(new ListDataListener() {

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

            //----------------------------------------------------------------------------------------------------
            @Override
            public void intervalRemoved(final ListDataEvent e) {
            }

            @Override
            public void intervalAdded(final ListDataEvent e) {
            }

            //----------------------------------------------------------------------------------------------------
            @Override
            public void contentsChanged(final ListDataEvent e) {
                final IGAOperatorConfigurator operator = (IGAOperatorConfigurator) operatorList.getSelectedValue();

                if (operatorList.getModel().getCheckedState(e.getIndex0()))
                    model.setSelectedGeneticOperator(operator);
                else
                    model.unsetSelectedGeneticOperator(operator);
            }
        });

        final JPanel gaSettingsPanel = FormsUtils.build("f:p:g", "0||" + "1||" + "2||" + "3||" + "4 f:p:g",
                populationPanel, stoppingPanel, fitnessPanel, selectorList, operatorList).getPanel();

        // the chromosome panel
        final JScrollPane treeScrPane = new JScrollPane();
        geneTree = new ListAsATree(model.getChromosomeTree());
        geneTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        geneTree.setCellRenderer(new ChromosomeTreeRenderer());

        geneTree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(final TreeSelectionEvent e) {
                final TreePath selectionPath = geneTree.getSelectionPath();

                boolean success = true;
                if (editedNode != null
                        && (selectionPath == null || !editedNode.equals(selectionPath.getLastPathComponent())))
                    success = modify();

                final DefaultTreeModel treeModel = model.getChromosomeTree();
                if (success) {
                    if (selectionPath != null) {
                        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath
                                .getLastPathComponent();
                        final ParameterOrGene userObj = (ParameterOrGene) node.getUserObject();

                        if (!node.equals(editedNode)) {
                            if (!node.isRoot()
                                    && selectionPath.getPathCount() == treeModel.getPathToRoot(node).length) {
                                editedNode = node;
                                edit(userObj);
                            } else {
                                editedNode = null;
                                geneTree.setSelectionPath(null);
                                resetSettings();
                                enableDisableSettings(false);
                            }
                        }
                    } else {
                        editedNode = null;
                        resetSettings();
                        enableDisableSettings(false);
                    }
                } else
                    geneTree.setSelectionPath(new TreePath(treeModel.getPathToRoot(editedNode)));

            }
        });

        treeScrPane.setViewportView(geneTree);
        treeScrPane.setBorder(null);
        treeScrPane.setViewportBorder(null);

        numberLabel = new JLabel("<html><b>Number of genes:</b> 0</html>");
        final JPanel treePanel = FormsUtils
                .build("~ f:p:g", "0||" + "1||" + "2 f:p:g", numberLabel, new Separator(""), treeScrPane)
                .getPanel();

        treePanel.setBorder(BorderFactory.createTitledBorder(""));

        geneSettingsValuePanel = new JPanel(new CardLayout());

        constantRButton = new JRadioButton("Constant");
        geneRButton = new JRadioButton("Gene");
        doubleGeneValueRangeRButton = new JRadioButton("Double value range");
        intGeneValueRangeRButton = new JRadioButton("Integer value range");
        listGeneValueRButton = new JRadioButton("Value list");
        GUIUtils.createButtonGroup(constantRButton, geneRButton, doubleGeneValueRangeRButton,
                intGeneValueRangeRButton, listGeneValueRButton);

        constantField = new JTextField();
        constantField.setActionCommand("CONST_FIELD");

        final JPanel constantPanel = FormsUtils
                .build("p ~ p:g", "[DialogBorder]01 p", "Constant value", constantField).getPanel();

        enumDefBox = new JComboBox<Object>(new DefaultComboBoxModel<Object>());

        final JPanel enumDefPanel = FormsUtils.build("p ~ p:g", "[DialogBorder]01 p", "Constant value", enumDefBox)
                .getPanel();

        leftEnumValueList = new JList<Object>(new DefaultListModel<Object>());
        rightEnumValueList = new JList<Object>(new DefaultListModel<Object>());
        final JScrollPane leftEnumValuePane = new JScrollPane(leftEnumValueList,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        final JScrollPane rightEnumValuePane = new JScrollPane(rightEnumValueList,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        leftEnumValuePane.setPreferredSize(new Dimension(125, 100)); //TODO: check
        rightEnumValuePane.setPreferredSize(new Dimension(125, 100)); //TODO: check

        addEnumButton = new DefaultJButton();
        addEnumButton.setOpaque(false);
        addEnumButton.setRolloverEnabled(true);
        addEnumButton.setIcon(ENUM_ADD_ICON);
        addEnumButton.setRolloverIcon(ENUM_ADD_ICON_RO);
        addEnumButton.setDisabledIcon(ENUM_ADD_ICON_DIS);
        addEnumButton.setBorder(null);
        addEnumButton.setBorderPainted(false);
        addEnumButton.setContentAreaFilled(false);
        addEnumButton.setFocusPainted(false);
        addEnumButton.setToolTipText("Add selected value");
        addEnumButton.setActionCommand("ADD_ENUM");

        removeEnumButton = new DefaultJButton();
        removeEnumButton.setOpaque(false);
        removeEnumButton.setRolloverEnabled(true);
        removeEnumButton.setIcon(ENUM_REMOVE_ICON);
        removeEnumButton.setRolloverIcon(ENUM_REMOVE_ICON_RO);
        removeEnumButton.setDisabledIcon(ENUM_REMOVE_ICON_DIS);
        removeEnumButton.setBorder(null);
        removeEnumButton.setBorderPainted(false);
        removeEnumButton.setContentAreaFilled(false);
        removeEnumButton.setFocusPainted(false);
        removeEnumButton.setToolTipText("Remove selected value");
        removeEnumButton.setActionCommand("REMOVE_ENUM");

        final JPanel enumListPanel = FormsUtils
                .build("p:g ~ p ' p ~ p:g", "[DialogBorder]0011 f:p:g||" + "_23_ p||", leftEnumValuePane,
                        rightEnumValuePane, removeEnumButton, addEnumButton)
                .getPanel();

        leftEnumValueList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(final MouseEvent e) {
                if (SwingUtilities.isLeftMouseButton(e) && e.getComponent().isEnabled() && e.getClickCount() == 2) {
                    final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();

                    for (final Object element : leftEnumValueList.getSelectedValuesList()) {
                        model.addElement(element);
                    }
                }
            }
        });
        rightEnumValueList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(final MouseEvent e) {
                if (SwingUtilities.isLeftMouseButton(e) && e.getComponent().isEnabled() && e.getClickCount() == 2) {
                    final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();

                    for (final Object element : rightEnumValueList.getSelectedValuesList()) {
                        model.removeElement(element);
                    }
                }
            }
        });

        fileTextField = new JTextField();
        fileTextField.setActionCommand("FILE_FIELD");
        fileTextField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(final KeyEvent e) {
                final char character = e.getKeyChar();
                final File file = new File(Character.isISOControl(character) ? fileTextField.getText()
                        : fileTextField.getText() + character);
                fileTextField.setToolTipText(file.getAbsolutePath());
            }
        });
        fileBrowseButton = new JButton(FileSystemView.getFileSystemView().getSystemIcon(new File(".")));
        fileBrowseButton.setActionCommand("FILE_BROWSE");

        final JPanel fileDefPanel = FormsUtils
                .build("p ~ p:g ' p", "[DialogBorder]012", "File", fileTextField, fileBrowseButton).getPanel();

        intMinField = new JTextField();
        intMinField.setActionCommand("INT_MIN");
        intMaxField = new JTextField();
        intMaxField.setActionCommand("INT_MAX");
        doubleMinField = new JTextField();
        doubleMinField.setActionCommand("D_MIN");
        doubleMaxField = new JTextField();
        doubleMaxField.setActionCommand("D_MAX");
        valuesArea = new JTextArea();
        valuesArea.setToolTipText("Please specify ' ' (space) separated values!");
        valuesArea.setLineWrap(true);
        valuesArea.setWrapStyleWord(true);
        final JScrollPane valuesDefScr = new JScrollPane(valuesArea,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        final JPanel doublePanel = FormsUtils.build("p ' f:p:g", "[DialogBorder]01 p ||" + "23 p", "Minimum value",
                doubleMinField, "Maximum value", doubleMaxField).getPanel();

        final JPanel intPanel = FormsUtils.build("p ' f:p:g", "[DialogBorder]01 p ||" + "23 p", "Minimum value",
                intMinField, "Maximum value", intMaxField).getPanel();

        final JPanel valuesPanel = FormsUtils
                .build("p ' p:g", "[DialogBorder]01 f:p:g", "Value list", CellConstraints.TOP, valuesDefScr)
                .getPanel();

        final JPanel emptyPanel = new JPanel();

        geneSettingsValuePanel.add(emptyPanel, "NULL");
        geneSettingsValuePanel.add(constantPanel, PARAM_SETTINGS_CONSTANT_VALUE_PANEL);
        geneSettingsValuePanel.add(enumDefPanel, PARAM_SETTINGS_ENUM_VALUE_PANEL);
        geneSettingsValuePanel.add(fileDefPanel, PARAM_SETTINGS_FILE_VALUE_PANEL);
        geneSettingsValuePanel.add(doublePanel, GENE_SETTINGS_DOUBLE_RANGE_VALUE_PANEL);
        geneSettingsValuePanel.add(intPanel, GENE_SETTINGS_INT_RANGE_VALUE_PANEL);
        geneSettingsValuePanel.add(valuesPanel, GENE_SETTINGS_LIST_VALUE_PANEL);
        geneSettingsValuePanel.add(enumListPanel, GENE_SETTINGS_ENUM_LIST_PANEL);

        final ItemListener itemListener = new ItemListener() {
            @Override
            public void itemStateChanged(final ItemEvent _) {
                if (editedNode != null) {
                    final CardLayout layout = (CardLayout) geneSettingsValuePanel.getLayout();
                    if (doubleGeneValueRangeRButton.isSelected())
                        layout.show(geneSettingsValuePanel, GENE_SETTINGS_DOUBLE_RANGE_VALUE_PANEL);
                    else if (intGeneValueRangeRButton.isSelected())
                        layout.show(geneSettingsValuePanel, GENE_SETTINGS_INT_RANGE_VALUE_PANEL);
                    else if (listGeneValueRButton.isSelected()) {
                        final ParameterOrGene param = (ParameterOrGene) editedNode.getUserObject();
                        if (param.getInfo().isEnum() || param.getInfo() instanceof MasonChooserParameterInfo) {
                            Object[] elements = null;
                            if (param.getInfo().isEnum()) {
                                @SuppressWarnings("unchecked")
                                final Class<Enum<?>> type = (Class<Enum<?>>) param.getInfo().getJavaType();
                                elements = type.getEnumConstants();
                            } else {
                                final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) param
                                        .getInfo();
                                elements = chooserInfo.getValidStrings();
                            }

                            final DefaultListModel<Object> leftEnumModel = (DefaultListModel<Object>) leftEnumValueList
                                    .getModel();
                            leftEnumModel.removeAllElements();
                            for (final Object object : elements) {
                                leftEnumModel.addElement(object);
                            }

                            final DefaultListModel<Object> rightEnumModel = (DefaultListModel<Object>) rightEnumValueList
                                    .getModel();
                            rightEnumModel.removeAllElements();
                            if (param.isGene()) {
                                for (final Object object : param.getGeneInfo().getValueRange()) {
                                    if (param.getInfo().isEnum()) {
                                        rightEnumModel.addElement(object);
                                    } else {
                                        final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) param
                                                .getInfo();
                                        rightEnumModel.addElement(chooserInfo.getValidStrings()[(Integer) object]);
                                    }
                                }
                            }
                            layout.show(geneSettingsValuePanel, GENE_SETTINGS_ENUM_LIST_PANEL);
                        } else {
                            layout.show(geneSettingsValuePanel, GENE_SETTINGS_LIST_VALUE_PANEL);
                        }
                    } else if (constantRButton.isSelected()) {
                        final ParameterOrGene param = (ParameterOrGene) editedNode.getUserObject();
                        if (param.getInfo().isEnum() || param.getInfo() instanceof MasonChooserParameterInfo)
                            layout.show(geneSettingsValuePanel, PARAM_SETTINGS_ENUM_VALUE_PANEL);
                        else if (param.getInfo().isFile())
                            layout.show(geneSettingsValuePanel, PARAM_SETTINGS_FILE_VALUE_PANEL);
                        else
                            layout.show(geneSettingsValuePanel, PARAM_SETTINGS_CONSTANT_VALUE_PANEL);
                    } else if (geneRButton.isSelected()) {
                        layout.show(geneSettingsValuePanel, "NULL");
                    }
                } else {
                    resetSettings();
                    enableDisableSettings(false);
                }
            }
        };
        constantRButton.addItemListener(itemListener);
        geneRButton.addItemListener(itemListener);
        doubleGeneValueRangeRButton.addItemListener(itemListener);
        intGeneValueRangeRButton.addItemListener(itemListener);
        listGeneValueRButton.addItemListener(itemListener);

        final JPanel selectPanel = FormsUtils.build("f:p:g", "0||" + "1||" + "2||" + "3||" + "4", constantRButton,
                geneRButton, doubleGeneValueRangeRButton, intGeneValueRangeRButton, listGeneValueRButton)
                .getPanel();

        final JPanel buttonsPanel = new JPanel();
        modifyButton = new JButton("Modify");
        modifyButton.setActionCommand("EDIT");
        cancelButton = new JButton("Cancel");
        cancelButton.setActionCommand("CANCEL");
        GUIUtils.addActionListener(new ActionListener() {

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

            //----------------------------------------------------------------------------------------------------
            @Override
            public void actionPerformed(ActionEvent e) {
                final String cmd = e.getActionCommand();
                if ("EDIT".equals(cmd))
                    edit();
                else if ("CANCEL".equals(cmd))
                    cancel();
                else if ("CONST_FIELD".equals(cmd) || "INT_MAX".equals(cmd) || "D_MAX".equals(cmd))
                    modifyButton.doClick();
                else if ("INT_MIN".equals(cmd))
                    intMaxField.grabFocus();
                else if ("D_MIN".equals(cmd))
                    doubleMaxField.grabFocus();
                else if ("FILE_BROWSE".equals(cmd))
                    chooseFile();
                else if ("ADD_ENUM".equals(cmd)) {
                    addEnum();
                } else if ("REMOVE_ENUM".equals(cmd)) {
                    removeEnum();
                }
            }

            //----------------------------------------------------------------------------------------------------
            private void edit() {
                if (editedNode != null)
                    geneTree.setSelectionPath(null);
            }

            //----------------------------------------------------------------------------------------------------
            private void cancel() {
                resetSettings();
                enableDisableSettings(false);
                editedNode = null;
                geneTree.setSelectionPath(null);
            }

            //----------------------------------------------------------------------------------------------------
            private void chooseFile() {
                final JFileChooser fileDialog = new JFileChooser(
                        !"".equals(fileTextField.getToolTipText()) ? fileTextField.getToolTipText()
                                : ParameterSweepWizard.getLastDir().getPath());
                if (!"".equals(fileTextField.getToolTipText()))
                    fileDialog.setSelectedFile(new File(fileTextField.getToolTipText()));
                int dialogResult = fileDialog.showOpenDialog(GASearchPanel.this);
                if (dialogResult == JFileChooser.APPROVE_OPTION) {
                    final File selectedFile = fileDialog.getSelectedFile();
                    if (selectedFile != null) {
                        ParameterSweepWizard.setLastDir(selectedFile.getAbsoluteFile().getParentFile());
                        fileTextField.setText(selectedFile.getName());
                        fileTextField.setToolTipText(selectedFile.getAbsolutePath());
                    }
                }
            }

            //----------------------------------------------------------------------------------------------------
            private void addEnum() {
                final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();

                for (final Object element : leftEnumValueList.getSelectedValuesList()) {
                    model.addElement(element);
                }

                leftEnumValueList.clearSelection();
            }

            //----------------------------------------------------------------------------------------------------
            private void removeEnum() {
                final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();

                for (final Object element : rightEnumValueList.getSelectedValuesList()) {
                    model.removeElement(element);
                }
            }

        }, modifyButton, cancelButton, constantField, fileTextField, intMinField, intMaxField, doubleMinField,
                doubleMaxField, fileBrowseButton, addEnumButton, removeEnumButton);
        buttonsPanel.add(modifyButton);
        buttonsPanel.add(cancelButton);

        final JPanel geneSetterPanel = FormsUtils
                .build("f:p:g", "0||" + "1 f:p:g||" + "2 p", selectPanel, geneSettingsValuePanel, buttonsPanel)
                .getPanel();

        geneSetterPanel.setBorder(BorderFactory.createTitledBorder(null, "Gene/parameter settings",
                TitledBorder.LEADING, TitledBorder.BELOW_TOP));

        localNewParametersButton = new JButton("Add new parameters...");
        localNewParametersButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                if (remoteNewParametersButton != null) {
                    remoteNewParametersButton.doClick();
                    model.addParametersToChromosomeTree();
                    updateNumberOfGenes();
                } else {
                    Utilities.userAlert(mainScrPane, "Sorry, this feature is not available.");
                }
            }
        });
        localNewParametersButton
                .setVisible(PlatformSettings.getGUIControllerForPlatform().isNewParametersEnabled());

        final JPanel rightTop = FormsUtils
                .build("f:p:g p ' p", "001 f:p:g||" + "_21 p", treePanel, geneSetterPanel, localNewParametersButton)
                .getPanel();
        rightTop.setBorder(
                BorderFactory.createTitledBorder(null, "Chromosome", TitledBorder.LEADING, TitledBorder.BELOW_TOP));

        final JPanel mainPanel = FormsUtils
                .build("p f:p:g", "01 f:p:g||" + "02 p", gaSettingsPanel, rightTop, operatorSettingsPanel)
                .getPanel();

        setLayout(new BorderLayout());
        mainScrPane = new JScrollPane(mainPanel);
        mainScrPane.setBorder(null);
        mainScrPane.setViewportBorder(null);
        add(mainScrPane, BorderLayout.CENTER);

        resetSettings();
        enableDisableSettings(false);
    }

    //----------------------------------------------------------------------------------------------------
    protected void showOperatorDetails(final JPanel operatorSettingsPanel, final IGAConfigurator operator) {
        if (operator != null) {
            CardLayout settingslayout = (CardLayout) operatorSettingsPanel.getLayout();
            settingslayout.show(operatorSettingsPanel, operator.getName());
            ((TitledBorder) operatorSettingsPanel.getBorder()).setTitle(operator.getName());
            operatorSettingsPanel.repaint();
        }
    }

    //------------------------------------------------------------------------------
    /** Enables/disables the parameter editing components of the page according to
     *  the value of <code>enabled</code>.
     */
    private void enableDisableSettings(final boolean enabled) {
        constantRButton.setEnabled(enabled);
        geneRButton.setEnabled(enabled);
        intGeneValueRangeRButton.setEnabled(enabled);
        doubleGeneValueRangeRButton.setEnabled(enabled);
        listGeneValueRButton.setEnabled(enabled);
        constantField.setEnabled(enabled);
        enumDefBox.setEnabled(enabled);
        addEnumButton.setEnabled(enabled);
        removeEnumButton.setEnabled(enabled);
        fileTextField.setEnabled(enabled);
        fileBrowseButton.setEnabled(enabled);
        intMinField.setEnabled(enabled);
        intMaxField.setEnabled(enabled);
        doubleMinField.setEnabled(enabled);
        doubleMaxField.setEnabled(enabled);
        valuesArea.setEnabled(enabled);
        modifyButton.setEnabled(enabled);
        cancelButton.setEnabled(enabled);
        localNewParametersButton
                .setEnabled(PlatformSettings.getGUIControllerForPlatform().isNewParametersEnabled() && !enabled);
    }

    //------------------------------------------------------------------------------
    /** Resets the parameter editing related components. */
    private void resetSettings() {
        constantRButton.setSelected(false);
        geneRButton.setSelected(false);
        intGeneValueRangeRButton.setSelected(false);
        doubleGeneValueRangeRButton.setSelected(false);
        listGeneValueRButton.setSelected(false);
        constantField.setText("");
        fileTextField.setText("");
        intMinField.setText("");
        intMaxField.setText("");
        doubleMinField.setText("");
        doubleMaxField.setText("");
        valuesArea.setText("");
        modifyButton.setEnabled(false);
        cancelButton.setEnabled(false);
        leftEnumValueList.setModel(new DefaultListModel<Object>());
        rightEnumValueList.setModel(new DefaultListModel<Object>());

        geneRButton.setVisible(false);
        intGeneValueRangeRButton.setVisible(true);
        doubleGeneValueRangeRButton.setVisible(true);
        listGeneValueRButton.setVisible(true);

        final CardLayout cl = (CardLayout) geneSettingsValuePanel.getLayout();
        cl.show(geneSettingsValuePanel, "NULL");
    }

    //----------------------------------------------------------------------------------------------------
    private void edit(final ParameterOrGene param) {
        enableDisableSettings(true);

        if (param.getInfo().isBoolean()) {
            geneRButton.setVisible(true);
            intGeneValueRangeRButton.setVisible(false);
            doubleGeneValueRangeRButton.setVisible(false);
            listGeneValueRButton.setVisible(false);
        }

        String view = PARAM_SETTINGS_CONSTANT_VALUE_PANEL;
        if (param.isGene()) {
            editGene(param);
            return;
        } else if (param.getInfo().isEnum() || param.getInfo() instanceof MasonChooserParameterInfo) {
            view = PARAM_SETTINGS_ENUM_VALUE_PANEL;
            intGeneValueRangeRButton.setEnabled(false);
            doubleGeneValueRangeRButton.setEnabled(false);
            listGeneValueRButton.setEnabled(true);
            constantRButton.setSelected(true);

            final ParameterInfo info = param.getInfo();
            final Object selected = info.getValue();
            Object[] elements = null;
            if (info.isEnum()) {
                @SuppressWarnings("unchecked")
                final Class<Enum<?>> type = (Class<Enum<?>>) info.getJavaType();
                elements = type.getEnumConstants();
            } else {
                final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) info;
                elements = chooserInfo.getValidStrings();
            }

            final DefaultComboBoxModel<Object> model = (DefaultComboBoxModel<Object>) enumDefBox.getModel();
            model.removeAllElements();
            for (final Object object : elements)
                model.addElement(object);

            if (info.isEnum())
                enumDefBox.setSelectedItem(selected);
            else
                enumDefBox.setSelectedIndex((Integer) selected);
        } else if (param.getInfo().isFile()) {
            view = PARAM_SETTINGS_FILE_VALUE_PANEL;
            constantRButton.setSelected(true);
            final File file = (File) param.getInfo().getValue();
            if (file != null) {
                fileTextField.setText(file.getName());
                fileTextField.setToolTipText(file.getAbsolutePath());
            }
        } else {
            constantRButton.setSelected(true);
            constantField.setText(param.getInfo().valuesToString());
        }

        final CardLayout cl = (CardLayout) geneSettingsValuePanel.getLayout();
        cl.show(geneSettingsValuePanel, view);
        if (!param.getInfo().isNumeric()) {
            intGeneValueRangeRButton.setEnabled(false);
            doubleGeneValueRangeRButton.setEnabled(false);
            boolean listEnabled = "String".equals(param.getInfo().getType()) || param.getInfo().isEnum()
                    || (param.getInfo() instanceof MasonChooserParameterInfo);
            listGeneValueRButton.setEnabled(listEnabled);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void editGene(final ParameterOrGene param) {
        final GeneInfo geneInfo = param.getGeneInfo();
        String view = null;
        if (GeneInfo.LIST.equals(geneInfo.getValueType())) {
            final ParameterInfo info = param.getInfo();
            if (info.isEnum() || info instanceof MasonChooserParameterInfo) {
                view = GENE_SETTINGS_ENUM_LIST_PANEL;
                intGeneValueRangeRButton.setEnabled(false);
                doubleGeneValueRangeRButton.setEnabled(false);
                listGeneValueRButton.setSelected(true);
                Object[] elements = null;
                if (info.isEnum()) {
                    @SuppressWarnings("unchecked")
                    final Class<Enum<?>> type = (Class<Enum<?>>) info.getJavaType();
                    elements = type.getEnumConstants();
                } else {
                    final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) info;
                    elements = chooserInfo.getValidStrings();
                }

                final DefaultListModel<Object> leftEnumModel = (DefaultListModel<Object>) leftEnumValueList
                        .getModel();
                leftEnumModel.removeAllElements();
                for (final Object object : elements)
                    leftEnumModel.addElement(object);

                final DefaultListModel<Object> rightEnumModel = (DefaultListModel<Object>) rightEnumValueList
                        .getModel();
                rightEnumModel.removeAllElements();
                for (final Object object : geneInfo.getValueRange()) {
                    if (info.isEnum()) {
                        rightEnumModel.addElement(object);
                    } else {
                        final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) info;
                        rightEnumModel.addElement(chooserInfo.getValidStrings()[(Integer) object]);
                    }
                }
            } else {
                view = GENE_SETTINGS_LIST_VALUE_PANEL;
                listGeneValueRButton.setSelected(true);
                valuesArea.setText(Utils.join(geneInfo.getValueRange(), " "));
            }
        } else if (GeneInfo.INTERVAL.equals(geneInfo.getValueType())) {
            if (geneInfo.isIntegerVals()) {
                view = GENE_SETTINGS_INT_RANGE_VALUE_PANEL;
                intGeneValueRangeRButton.setSelected(true);
                intMinField.setText(String.valueOf(geneInfo.getMinValue()));
                intMaxField.setText(String.valueOf(geneInfo.getMaxValue()));
            } else {
                view = GENE_SETTINGS_DOUBLE_RANGE_VALUE_PANEL;
                doubleGeneValueRangeRButton.setSelected(true);
                doubleMinField.setText(String.valueOf(geneInfo.getMinValue()));
                doubleMaxField.setText(String.valueOf(geneInfo.getMaxValue()));
            }
        } else {
            view = "NULL";
            geneRButton.setSelected(true);
        }

        final CardLayout cl = (CardLayout) geneSettingsValuePanel.getLayout();
        cl.show(geneSettingsValuePanel, view);
    }

    //----------------------------------------------------------------------------------------------------
    private String[] checkInput(final ParameterOrGene param) {
        final List<String> errors = new ArrayList<String>();

        if (constantRButton.isSelected()) {
            final ParameterInfo info = param.getInfo();

            if (info.isEnum() || info instanceof MasonChooserParameterInfo) {
                // well, the combo box must contain a valid value
            } else if (info.isFile()) {
                if (fileTextField.getText().trim().isEmpty())
                    Logger.logWarning("Empty string was specified as file parameter "
                            + info.getName().replaceAll("([A-Z])", " $1"));

                final File file = new File(fileTextField.getToolTipText());
                if (!file.exists())
                    errors.add("File " + fileTextField.getToolTipText() + " does not exist.");
            } else if (constantField.getText().trim().equals(""))
                errors.add("'Constant value' cannot be empty.");
            else {
                final boolean valid = ParameterInfo.isValid(constantField.getText().trim(), info.getType());
                if (!valid)
                    errors.add("'Constant value' must be a valid " + getTypeText(info.getType()) + ".");

                errors.addAll(PlatformSettings.additionalParameterCheck(info,
                        new String[] { constantField.getText().trim() }, ParameterInfo.CONST_DEF));
            }
        } else if (intGeneValueRangeRButton.isSelected()) {
            final String minFieldText = intMinField.getText();
            final String maxFieldText = intMaxField.getText();
            Long minValue = null;
            Long maxValue = null;

            if (minFieldText == null || minFieldText.trim().isEmpty())
                errors.add("'Minimum value' cannot be empty.");
            else {
                try {
                    minValue = new Long(minFieldText.trim());

                    final boolean valid = ParameterInfo.isValid(minFieldText, param.getInfo().getType());
                    if (!valid)
                        errors.add(
                                "'Minimum value' must be a valid " + getTypeText(param.getInfo().getType()) + ".");

                    errors.addAll(PlatformSettings.additionalParameterCheck(param.getInfo(),
                            new String[] { minFieldText.trim() }, ParameterInfo.CONST_DEF));
                } catch (final NumberFormatException _) {
                    errors.add("'Minimum value' must be a valid integer number.");
                }
            }

            if (maxFieldText == null || maxFieldText.trim().isEmpty())
                errors.add("'Maximum value' cannot be empty.");
            else {
                try {
                    maxValue = new Long(maxFieldText.trim());

                    final boolean valid = ParameterInfo.isValid(maxFieldText, param.getInfo().getType());
                    if (!valid)
                        errors.add(
                                "'Maximum value' must be a valid " + getTypeText(param.getInfo().getType()) + ".");

                    errors.addAll(PlatformSettings.additionalParameterCheck(param.getInfo(),
                            new String[] { maxFieldText.trim() }, ParameterInfo.CONST_DEF));
                } catch (final NumberFormatException _) {
                    errors.add("'Maximum value' must be a valid integer number.");
                }
            }

            if (minValue != null && maxValue != null) {
                if (minValue.longValue() > maxValue.longValue())
                    errors.add("Please specify a non-empty interval!");
            }
        } else if (doubleGeneValueRangeRButton.isSelected()) {
            final String minFieldText = doubleMinField.getText();
            final String maxFieldText = doubleMaxField.getText();
            Double minValue = null;
            Double maxValue = null;

            if (minFieldText == null || minFieldText.trim().isEmpty())
                errors.add("'Minimum value' cannot be empty.");
            else {
                try {
                    minValue = new Double(minFieldText.trim());

                    final boolean valid = ParameterInfo.isValid(minFieldText, param.getInfo().getType());
                    if (!valid)
                        errors.add(
                                "'Minimum value' must be a valid " + getTypeText(param.getInfo().getType()) + ".");

                    errors.addAll(PlatformSettings.additionalParameterCheck(param.getInfo(),
                            new String[] { minFieldText.trim() }, ParameterInfo.CONST_DEF));
                } catch (final NumberFormatException _) {
                    errors.add("'Minimum value' must be a valid number.");
                }
            }

            if (maxFieldText == null || maxFieldText.trim().isEmpty())
                errors.add("'Maximum value' cannot be empty.");
            else {
                try {
                    maxValue = new Double(maxFieldText.trim());

                    final boolean valid = ParameterInfo.isValid(maxFieldText, param.getInfo().getType());
                    if (!valid)
                        errors.add(
                                "'Maximum value' must be a valid " + getTypeText(param.getInfo().getType()) + ".");

                    errors.addAll(PlatformSettings.additionalParameterCheck(param.getInfo(),
                            new String[] { maxFieldText.trim() }, ParameterInfo.CONST_DEF));
                } catch (final NumberFormatException _) {
                    errors.add("'Maximum value' must be a valid number.");
                }
            }

            if (minValue != null && maxValue != null) {
                if (minValue.doubleValue() > maxValue.doubleValue())
                    errors.add("Please specify a non-empty interval!");
            }

        } else if (listGeneValueRButton.isSelected()) {
            if (param.getInfo().isEnum() || param.getInfo() instanceof MasonChooserParameterInfo) {
                final ListModel<Object> model = rightEnumValueList.getModel();
                if (model.getSize() == 0) {
                    errors.add("The list on the right cannot be empty.");
                }
            } else if (valuesArea.getText() == null || valuesArea.getText().trim().isEmpty())
                errors.add("'Value list' cannot be empty.");
            else {
                try {
                    final List<Object> valueList = new ArrayList<Object>();
                    String values = valuesArea.getText().trim();
                    values = values.replaceAll("\\s+", " ");
                    final StringTokenizer tokenizer = new StringTokenizer(values, " ");
                    while (tokenizer.hasMoreTokens()) {
                        final String strValue = tokenizer.nextToken();

                        final boolean valid = ParameterInfo.isValid(strValue, param.getInfo().getType());
                        if (!valid)
                            errors.add("'" + strValue + "' is not a valid " + getTypeText(param.getInfo().getType())
                                    + ".");

                        valueList.add(parseListElement(param.getInfo().getJavaType(), strValue));
                    }

                    errors.addAll(PlatformSettings.additionalParameterCheck(param.getInfo(), values.split(" "),
                            ParameterInfo.LIST_DEF));
                } catch (final NumberFormatException _) {
                    errors.add("All element of the value list must be a valid number.");
                }
            }
        }

        return errors.isEmpty() ? null : errors.toArray(new String[0]);
    }

    //------------------------------------------------------------------------------
    /** Returns the appropriate error message part according to the value of <code>type</code>. */
    private String getTypeText(final 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 + ".";
    }

    //----------------------------------------------------------------------------------------------------
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Object parseListElement(final Class<?> type, final String strValue) {
        if (String.class.equals(type))
            return strValue;

        if (Enum.class.isAssignableFrom(type)) {
            final Class<? extends Enum> clazz = (Class<? extends Enum>) type;
            return Enum.valueOf(clazz, strValue);
        }

        if (type.equals(Double.class) || type.equals(Float.class) || type.equals(Double.TYPE)
                || type.equals(Float.TYPE))
            return Double.parseDouble(strValue);

        return Long.parseLong(strValue);
    }

    //----------------------------------------------------------------------------------------------------
    private boolean modify() {
        final ParameterOrGene userObj = (ParameterOrGene) editedNode.getUserObject();

        final String[] errors = checkInput(userObj);
        if (errors != null && errors.length != 0) {
            Utilities.userAlert(mainScrPane, (Object) errors);
            return false;
        } else {
            modifyParameterOrGene(userObj);
            resetSettings();

            final DefaultTreeModel model = (DefaultTreeModel) geneTree.getModel();
            model.nodeStructureChanged(editedNode);

            editedNode = null;

            updateNumberOfGenes();
            enableDisableSettings(false);
            return true;
        }
    }

    //----------------------------------------------------------------------------------------------------
    public boolean closeActiveModification() {
        return editedNode != null ? modify() : true;
    }

    //------------------------------------------------------------------------------
    private void modifyParameterOrGene(final ParameterOrGene param) {
        final ParameterInfo info = param.getInfo();
        if (constantRButton.isSelected()) {
            if (info.isEnum())
                param.setConstant(enumDefBox.getSelectedItem());
            else if (info instanceof MasonChooserParameterInfo)
                param.setConstant(enumDefBox.getSelectedIndex());
            else if (info.isFile())
                param.setConstant(ParameterInfo.getValue(fileTextField.getToolTipText(), info.getType()));
            else
                param.setConstant(ParameterInfo.getValue(constantField.getText().trim(), info.getType()));
        } else if (intGeneValueRangeRButton.isSelected()) {
            final Long minValue = new Long(intMinField.getText().trim());
            final Long maxValue = new Long(intMaxField.getText().trim());
            param.setGene(minValue, maxValue);
        } else if (doubleGeneValueRangeRButton.isSelected()) {
            final Double minValue = new Double(doubleMinField.getText().trim());
            final Double maxValue = new Double(doubleMaxField.getText().trim());
            param.setGene(minValue, maxValue);
        } else if (listGeneValueRButton.isSelected()) {
            if (info.isEnum()) {
                final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();
                final List<Object> result = new ArrayList<Object>();
                for (int i = 0; i < model.size(); result.add(model.get(i++)))
                    ;
                param.setGene(result);
            } else if (info instanceof MasonChooserParameterInfo) {
                final MasonChooserParameterInfo chooserInfo = (MasonChooserParameterInfo) info;
                final String[] validStrings = chooserInfo.getValidStrings();
                final List<Object> result = new ArrayList<Object>();
                final DefaultListModel<Object> model = (DefaultListModel<Object>) rightEnumValueList.getModel();
                for (int i = 0; i < model.size(); ++i) {
                    int idx = -1;
                    for (int j = 0; j < validStrings.length; ++j) {
                        if (validStrings[j].equals(model.get(i))) {
                            idx = j;
                            break;
                        }
                    }

                    if (idx >= 0)
                        result.add(idx);
                }
                param.setGene(result);
            } else {
                final List<Object> valueList = new ArrayList<Object>();
                String values = valuesArea.getText().trim();
                values = values.replaceAll("\\s+", " ");
                final StringTokenizer tokenizer = new StringTokenizer(values, " ");
                while (tokenizer.hasMoreTokens())
                    valueList.add(parseListElement(param.getInfo().getJavaType(), tokenizer.nextToken()));
                param.setGene(valueList);
            }
        } else if (geneRButton.isSelected()) {
            param.setBooleanGene();
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void updateNumberOfGenes() {
        int count = 0;

        final DefaultTreeModel treeModel = (DefaultTreeModel) geneTree.getModel();
        final DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
        @SuppressWarnings("rawtypes")
        final Enumeration nodes = root.breadthFirstEnumeration();
        nodes.nextElement();

        while (nodes.hasMoreElements()) {
            final DefaultMutableTreeNode node = (DefaultMutableTreeNode) nodes.nextElement();
            final ParameterOrGene userObj = (ParameterOrGene) node.getUserObject();
            if (userObj.isGene())
                count++;
        }

        numberLabel.setText("<html><b>Number of genes:</b> " + count + "</html>");
    }
}