Package jcgp.gui.settings

Source Code of jcgp.gui.settings.SettingsPane

package jcgp.gui.settings;

import java.io.File;
import java.util.ArrayList;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import jcgp.JCGP;
import jcgp.backend.function.FunctionSet;
import jcgp.backend.modules.es.EvolutionaryStrategy;
import jcgp.backend.modules.mutator.Mutator;
import jcgp.backend.modules.problem.Problem;
import jcgp.backend.modules.problem.TestCaseProblem;
import jcgp.backend.parameters.Parameter;
import jcgp.gui.GUI;
import jcgp.gui.constants.Constants;
import jcgp.gui.settings.parameters.GUIParameter;
import jcgp.gui.settings.testcase.TestCaseTable;

/**
* This is a fairly hefty class which encapsulates the entire right-hand
* control pane. It contains base parameters, module selectors and their
* associated parameters, flow controls and file loading/saving buttons.
* <br><br>
* A single instance of this class is used in {@code GUI}.
*
*
* @author Eduardo Pedroni
*
*/
public class SettingsPane extends AnchorPane {
 
  /*
   * The primary containers, these make up each section of the settings pane.
   */
  private VBox mainContainer;
  private VBox baseParameterPane, eaPane, mutatorPane, problemPane;
  private VBox nodeFunctions;
 
  // all buttons
  private Button runPause = new Button("Run"), step = new Button("Step"), reset = new Button("Reset");
  private Button loadParameters = new Button("Load parameters"), loadChromosome = new Button("Load chromosome"), saveChromosome = new Button("Save chromosome");
 
  // this is a list of parameters used for parameter validity checks
  private ArrayList<GUIParameter<?>> parameters = new ArrayList<GUIParameter<?>>();
 
  // the test case table stage
  private TestCaseTable testCaseTable;
 
  // a reference to the parent GUI
  private GUI gui;
 
  private int currentArity;
   
  /**
   * Create a new instance of {@code SettingsPane} associated
   * with the specified {@code GUI} object.
   *
   * @param gui a reference to this object's parent.
   */
  public SettingsPane(GUI gui) {
    super();
    this.gui = gui;
   
    // acquire a reference to jcgp, for convenience
    final JCGP jcgp = gui.getExperiment();
   
    // make the overarching container
    mainContainer = new VBox(8);
    mainContainer.setPadding(new Insets(5, Constants.RESIZE_MARGIN, 0, 2));
   
    setMinWidth(Constants.SETTINGS_MIN_WIDTH);
    setPrefWidth(Constants.SETTINGS_MIN_WIDTH);
   
    // initialise all sub-divisions
    initialiseBaseParameters(jcgp);
   
    initialiseEAParameters(jcgp);
   
    initialiseMutatorParameters(jcgp);
   
    initialiseProblemTypeParameters(jcgp, gui);
   
    createControls(gui);
   
    // prepare the scroll pane
    ScrollPane scroll = new ScrollPane();
    scroll.setFitToWidth(true);
    scroll.setContent(mainContainer);
    scroll.setStyle("-fx-background-color: #FFFFFF");
   
    // anchor the scroll pane to itself, bearing in mind the resize margin
    AnchorPane.setTopAnchor(scroll, 0.0);
    AnchorPane.setBottomAnchor(scroll, 0.0);
    AnchorPane.setRightAnchor(scroll, 0.0);
    AnchorPane.setLeftAnchor(scroll, Constants.RESIZE_MARGIN);
   
    // add the scroll pane, all done!
    getChildren().add(scroll);
  }

  /**
   * Creates the base parameters pane
   *
   * @param jcgp
   */
  private void initialiseBaseParameters(JCGP jcgp) {
    baseParameterPane = new VBox(2);
   
    Text header = new Text("Base Parameters");
    header.setFont(Font.font("Arial", 14));
    header.setUnderline(true);
   
    baseParameterPane.getChildren().add(header);

    parameters.add(GUIParameter.create(jcgp.getResources().getRowsParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getColumnsParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getInputsParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getOutputsParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getLevelsBackParameter(), this));
   
    GUIParameter<?> gp = GUIParameter.create(jcgp.getResources().getPopulationSizeParameter(), this);
    gp.setPadding(new Insets(0, 0, 10, 0));
    parameters.add(gp);
   
    parameters.add(GUIParameter.create(jcgp.getResources().getCurrentGenerationParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getGenerationsParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getCurrentRunParameter(), this));
   
    gp = GUIParameter.create(jcgp.getResources().getRunsParameter(), this);
    gp.setPadding(new Insets(0, 0, 10, 0));
    parameters.add(gp);
   
    parameters.add(GUIParameter.create(jcgp.getResources().getSeedParameter(), this));
    parameters.add(GUIParameter.create(jcgp.getResources().getReportIntervalParameter(), this));
   
    baseParameterPane.getChildren().addAll(parameters);
    mainContainer.getChildren().add(baseParameterPane);
  }

  private void initialiseEAParameters(final JCGP jcgp) {
    eaPane = new VBox(2);
   
    Text header = new Text("Evolutionary Strategy");
    header.setFont(Font.font("Arial", 14));
    header.setUnderline(true);
   
    final ComboBox<EvolutionaryStrategy> esCBox = new ComboBox<EvolutionaryStrategy>();
    esCBox.getItems().addAll(jcgp.getEvolutionaryStrategies());
    esCBox.getSelectionModel().select(jcgp.getEvolutionaryStrategy());
    esCBox.prefWidthProperty().bind(mainContainer.widthProperty());
   
    final VBox eaParameters = new VBox(2);
   
    refreshParameters(jcgp.getEvolutionaryStrategy().getLocalParameters(), eaParameters);
   
    esCBox.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        jcgp.setEvolutionaryStrategy(esCBox.getSelectionModel().getSelectedIndex());
        refreshParameters(esCBox.getSelectionModel().getSelectedItem().getLocalParameters(), eaParameters);
        gui.flushConsole();
      }
    });
   
    eaPane.getChildren().addAll(header, esCBox, eaParameters)
    mainContainer.getChildren().add(eaPane);
  }

  private void initialiseMutatorParameters(final JCGP jcgp) {
    mutatorPane = new VBox(2);
   
    Text header = new Text("Mutator");
    header.setFont(Font.font("Arial", 14));
    header.setUnderline(true);
   
    final ComboBox<Mutator> mutatorCBox = new ComboBox<Mutator>();
    mutatorCBox.getItems().addAll(jcgp.getMutators());
    mutatorCBox.getSelectionModel().select(jcgp.getMutator());
    mutatorCBox.prefWidthProperty().bind(mainContainer.widthProperty());
   
    final VBox mutatorParameters = new VBox(2);
    refreshParameters(jcgp.getMutator().getLocalParameters(), mutatorParameters);
   
    mutatorCBox.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        jcgp.setMutator(mutatorCBox.getSelectionModel().getSelectedIndex());
        refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters(), mutatorParameters);
        gui.flushConsole();
      }
    });
   
    mutatorPane.getChildren().addAll(header, mutatorCBox, mutatorParameters);
    mainContainer.getChildren().add(mutatorPane);
  }
 
  private void initialiseProblemTypeParameters(final JCGP jcgp, final GUI gui) {
    updateArity();
   
    problemPane= new VBox(2);
   
    Text header = new Text("Problem Type");
    header.setFont(Font.font("Arial", 14));
    header.setUnderline(true);
   
    final ComboBox<Problem> problemCBox = new ComboBox<Problem>();
    problemCBox.getItems().addAll(jcgp.getProblems());
    problemCBox.getSelectionModel().select(jcgp.getProblem());
    problemCBox.prefWidthProperty().bind(mainContainer.widthProperty());
   
    final VBox problemParameters = new VBox(2);
    problemParameters.setPadding(new Insets(0, 0, 4, 0));
    refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters);
   
    final HBox testCaseControlContainer = new HBox(2);
   
    final Button showTestCaseButton = makeTestCaseButton();
    final Button loadProblemDataButton = makeLoadTestCaseButton();
    HBox.setHgrow(showTestCaseButton, Priority.ALWAYS);
    showTestCaseButton.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(loadProblemDataButton, Priority.ALWAYS);
    loadProblemDataButton.setMaxWidth(Double.MAX_VALUE);
   
    if (jcgp.getProblem() instanceof TestCaseProblem<?>) {
      testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadProblemDataButton);
      remakeTestCaseTable();
    } else {
      testCaseControlContainer.getChildren().add(loadProblemDataButton);
    }
   
    nodeFunctions = new VBox(2);
    nodeFunctions.setPadding(new Insets(0, 0, 4, 0));
    refreshFunctions();
   
    problemCBox.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        jcgp.setProblem(problemCBox.getSelectionModel().getSelectedIndex());
        updateArity();
        refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters);
        if (testCaseTable != null) {
          testCaseTable.close();
        }
        gui.setEvaluating(false);
        refreshFunctions();
        testCaseControlContainer.getChildren().clear();
        if (jcgp.getProblem() instanceof TestCaseProblem) {
          testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadProblemDataButton);
          remakeTestCaseTable();
        } else {
          testCaseControlContainer.getChildren().add(loadProblemDataButton);
        }
        gui.reset();
      }
    });
   
    problemPane.getChildren().addAll(header, problemCBox, problemParameters, nodeFunctions, testCaseControlContainer);
    mainContainer.getChildren().add(problemPane);
   
  }
 
  private Button makeLoadTestCaseButton() {
    Button b = new Button("Load data");
    b.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        FileChooser fc = new FileChooser();
        fc.setTitle("Open problem file...");
        fc.getExtensionFilters().add(new ExtensionFilter("CGP " + gui.getExperiment().getProblem() + " files", "*" + ((TestCaseProblem<?>) gui.getExperiment().getProblem()).getFileExtension()));
        fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*"));
        File chrFile = fc.showOpenDialog(gui.getStage());
        if (chrFile != null) {
          gui.getExperiment().loadProblemData(chrFile);
          remakeTestCaseTable();
          gui.reDraw();
        }
      }
    });
    return b;
  }

  private Button makeTestCaseButton() {
    Button b = new Button("Show data");
    b.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        testCaseTable.show();
      }
    });
    return b;
  }

  private void createControls(final GUI gui) {
    Text header = new Text("Experiment controls");
    header.setFont(Font.font("Arial", 14));
    header.setUnderline(true);
   
    final VBox controls = new VBox(2);
    controls.setFillWidth(true);
   
    final HBox flowButtons = new HBox(2);
    runPause.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {       
        gui.runPause();
      }
    });
   
    step.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        gui.step();
      }
    });
   
    reset.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        gui.reset();
      }
    });
   
    HBox.setHgrow(runPause, Priority.ALWAYS);
    runPause.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(step, Priority.ALWAYS);
    step.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(reset, Priority.ALWAYS);
    reset.setMaxWidth(Double.MAX_VALUE);
   
    flowButtons.getChildren().addAll(runPause, step, reset);
    flowButtons.setPadding(new Insets(0, 0, 10, 0));
   
    loadParameters.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {       
        FileChooser fc = new FileChooser();
        fc.setTitle("Open .par file...");
        fc.getExtensionFilters().add(new ExtensionFilter("CGP parameter files", "*.par"));
        fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*"));
        File parFile = fc.showOpenDialog(gui.getStage());
        if (parFile != null) {
          gui.getExperiment().loadParameters(parFile);
          gui.reDraw();
          refreshFunctions();
        }
        gui.flushConsole();
      }
    });
   
    loadChromosome.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        FileChooser fc = new FileChooser();
        fc.setTitle("Load .chr file...");
        fc.getExtensionFilters().add(new ExtensionFilter("CGP chromosome files", "*.chr"));
        fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*"));
        File chrFile = fc.showOpenDialog(gui.getStage());
        if (chrFile != null) {
          gui.getExperiment().loadChromosome(chrFile, gui.getChromosomeIndex());
          gui.reDraw();
        }
        gui.flushConsole();
      }
    });
    saveChromosome.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        FileChooser fc = new FileChooser();
        fc.setTitle("Save .chr file...");
        fc.getExtensionFilters().add(new ExtensionFilter("CGP chromosome files", "*.chr"));
        fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*"));
        File chrFile = fc.showSaveDialog(gui.getStage());
        if (chrFile != null) {
          gui.getExperiment().saveChromosome(chrFile, gui.getChromosomeIndex());
        }
        gui.flushConsole();
      }
    });
   
    HBox.setHgrow(loadParameters, Priority.ALWAYS);
    loadParameters.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(loadChromosome, Priority.ALWAYS);
    loadChromosome.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(saveChromosome, Priority.ALWAYS);
    saveChromosome.setMaxWidth(Double.MAX_VALUE);
   
    controls.getChildren().addAll(header, flowButtons, loadParameters, loadChromosome, saveChromosome);
   
    mainContainer.getChildren().add(controls)
  }
 
  /**
   * Builds {@code GUIParameter}s and adds them to the provided {@code VBox}.
   * The parameters built are taken from the specified list.
   *
   * @param newParameters the list of parameters to add.
   * @param container the container to add the parameters to.
   */
  private void refreshParameters(ArrayList<Parameter<?>> newParameters, VBox container) {
    // remove what is currently in the container from the parameter list
    parameters.removeAll(container.getChildren());
    // remove everything in the container
    container.getChildren().clear();
    // if there are parameters to add, add them all
    if (newParameters != null) {
      for (int i = 0; i < newParameters.size(); i++) {
        // factory method returns the right subtype of GUIParameter
        GUIParameter<?> guiParameter = GUIParameter.create(newParameters.get(i), this);
        // make sure to add it to the parameter list as well
        parameters.add(guiParameter);
        container.getChildren().add(guiParameter);
      }
    }
    // do a quick refresh just in case something is invalid
    revalidateParameters();
  }
 
  /**
   * This method handles a problem type change by updating the list of allowed
   * node functions.
   * <br><br>
   * It does so by creating new checkboxes for each function in the function set.
   */
  private void refreshFunctions() {
    // remove all current functions
    nodeFunctions.getChildren().clear();
    CheckBox checkBox;
    // get a reference to the function set
    final FunctionSet functionSet = gui.getExperiment().getResources().getFunctionSet();
    for (int i = 0; i < functionSet.getTotalFunctionCount(); i++) {
      // add a checkbox for each function
      checkBox = new CheckBox(functionSet.getFunction(i).toString());
      checkBox.setId(String.valueOf(i));
      // make sure the selection matches the function set
      checkBox.setSelected(functionSet.isEnabled(functionSet.getFunction(i)));
      final int index = i;
      // set listener so function set gets updated if the checkboxes change
      checkBox.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
          if (((CheckBox) event.getSource()).isSelected()) {
            functionSet.enableFunction(index);
          } else {
            functionSet.disableFunction(index);
          }
          gui.updateFunctionSelector();
          revalidateParameters();
        }
      });
      // add the new checkbox
      nodeFunctions.getChildren().add(checkBox);
    }
    // make sure function selector has all functions
    gui.updateFunctionSelector();
  }
 
  /**
   * @return true if the experiment is currently evolving something, false otherwise.
   */
  public boolean isExperimentRunning() {
    return gui.isWorking();
  }
 
  /**
   *
   * @return true if the experiment needs to be reset, false if otherwise.
   */
  public boolean isResetRequired() {
    for (GUIParameter<?> parameter : parameters) {
      if (parameter.requiresReset()) {
        return true;
      }
    }
    if (arityChanged()) {
      return true;
    }
    return false;
  }
 
  /**
   * @return true if no parameters have their status set to ParameterStatus.INVALID.
   */
  public boolean areParametersValid() {
    for (GUIParameter<?> parameter : parameters) {
      if (!parameter.isValid()) {
        return false;
      }
    }
    return true;
  }
 
  /**
   * Calls validate() on every parameter. This is called whenever a parameter changes,
   * so that other parameters update their status in case they were dependent on the
   * changed parameter.
   * <br><br>
   * This also disables the controls if a reset is necessary, preventing the experiment
   * from running until it has happened.
   */
  public void revalidateParameters() {
    boolean disableControls = false;
    for (GUIParameter<?> parameter : parameters) {
      parameter.validate();
      if (parameter.requiresReset()) {
        disableControls = true;
      }
    }
    if (arityChanged()) {
      disableControls = true;
    }
   
    runPause.setDisable(disableControls);
    step.setDisable(disableControls);
  }
 
  /**
   * Calls applyValue() on every parameter. This is called when a reset occurs, so that
   * the new value will be used as a reference instead of the old reference value.
   * <br><br>
   * It also closes the test case table, just in case.
   */
  public void applyParameters() {
    for (GUIParameter<?> parameter : parameters) {
      parameter.applyValue();
    }
    updateArity();
    if (testCaseTable != null) {
      testCaseTable.close();
    }
  }

  /**
   * Updates all of the controls to their appropriate state based on the status of the
   * experiment, in order to prevent inappropriate operations if the experiment is
   * running or finished.
   *
   * @param running true if the experiment is running.
   * @param finished true if the experiment is finished.
   */
  public void updateControls(boolean running, boolean finished) {
    baseParameterPane.setDisable(running);
    eaPane.setDisable(running);
    mutatorPane.setDisable(running);
    problemPane.setDisable(running);
   
    runPause.setText(running ? "Pause" : "Run");
    runPause.setDisable(finished);
    step.setDisable(running || finished);
    reset.setDisable(running);
   
    loadParameters.setDisable(running);
    loadChromosome.setDisable(running);
    saveChromosome.setDisable(running);
   
    testCaseTable.getTable().setDisable(running);
  }
 
  private void remakeTestCaseTable() {
    boolean wasShowing = false;
    if (testCaseTable != null) {
      wasShowing = testCaseTable.isShowing();
      testCaseTable.close();
    }
    testCaseTable = new TestCaseTable((TestCaseProblem<Object>) gui.getExperiment().getProblem(), gui);
    if (wasShowing) {
      testCaseTable.show();
    }
  }
 
  public TestCaseTable getTestCaseTable() {
    return testCaseTable;
  }
 
  private void updateArity() {
    currentArity = gui.getExperiment().getProblem().getFunctionSet().getMaxArity();
  }
 
  private boolean arityChanged() {
    return currentArity != gui.getExperiment().getProblem().getFunctionSet().getMaxArity();
  }
}
TOP

Related Classes of jcgp.gui.settings.SettingsPane

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.