diff options
Diffstat (limited to 'src/jcgp/gui')
25 files changed, 0 insertions, 3579 deletions
| diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java deleted file mode 100644 index 689f38c..0000000 --- a/src/jcgp/gui/GUI.java +++ /dev/null @@ -1,477 +0,0 @@ -package jcgp.gui; - -import javafx.application.Application; -import javafx.application.Platform; -import javafx.concurrent.Service; -import javafx.concurrent.Task; -import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.Pane; -import javafx.stage.Stage; -import javafx.stage.WindowEvent; -import jcgp.JCGP; -import jcgp.backend.modules.problem.TestCaseProblem.TestCase; -import jcgp.backend.resources.Resources; -import jcgp.gui.console.ConsolePane; -import jcgp.gui.dragresize.HorizontalDragResize; -import jcgp.gui.dragresize.VerticalDragResize; -import jcgp.gui.population.FunctionSelector; -import jcgp.gui.population.GUINode; -import jcgp.gui.population.PopulationPane; -import jcgp.gui.settings.SettingsPane; - -/** - * Main class for the graphical user interface (GUI). - * <br><br> - * This class declares the main method used when running the GUI. - * In addition, all main GUI panes are declared and instantiated here. - * <br><br> - * The user interface is divided into 3 main components: the node grid - * ({@link PopulationPane}), the control pane ({@link SettingsPane}) and - * the console ({@link ConsolePane}). Click on any of the links in - * brackets to see more information about each interface component. - * <br><br> - * This class also contains the instance of JCGP responsible for - * running the experiments in GUI mode. JCGP's execution must be delegated - * to a separate thread so that the GUI remains unblocked. This is done using - * a JavaFX {@code Service} which calls {@code nextGeneration()} in a loop - * until it is interrupted by the main JavaFX thread. - * <br> - * This service also handles flushing the console in a thread safe way. This - * is done by synchronizing the {@code nextGeneration()} and {@code flush()} - * method calls on a lock object. - *  - * @author Eduardo Pedroni - * - */ -public class GUI extends Application { -     -	/* -	 * Actual GUI elements -	 */ -	private Stage stage; -	private PopulationPane populationPane; -	private ConsolePane console; -	private SettingsPane settingsPane; -	private final FunctionSelector functionSelector; -	 -	/* -	 * Flow control objects -	 */ -	private boolean running = false; -	private final Object printLock = new Object(); -	private Service<Void> jcgpService; -	private Runnable consoleFlush; -	 -	/* -	 * The experiment itself -	 */ -	private final JCGP jcgp; -	 -	public static Resources resources; -	 -	 -	/** -	 * Start JCGP with the user interface. -	 *  -	 * @param args no arguments are used. -	 */ -	public static void main(String[] args) { -		// not much to do, simply launch the JavaFX application -		launch(); -	} -	 -	/** -	 * Makes a new instance of GUI. This initialises the JCGP experiment and  -	 * instantiates the function selector. It also creates the console flush task -	 * and the service responsible for running the JCGP experiment. -	 */ -	public GUI() { -		jcgp = new JCGP(); -		resources = jcgp.getResources(); -		functionSelector = new FunctionSelector(jcgp.getResources().getFunctionSet()); -		 -		/* -		 * This task flushes the console in a thread-safe way. -		 * The problem is that this task is executed using Platform.runLater() -		 * to ensure that the flush itself happens on the JavaFX thread. However, -		 * runLater() is not guaranteed to run anytime soon. If the time taken for -		 * jcgp to perform a single generation is shorter than the time taken for -		 * this task to be executed by the platform, consoleFlush tasks will be  -		 * scheduled faster than they can be executed and the console will eventually  -		 * freeze.  -		 *  -		 * This is addressed by synchronizing the flushes with each nextGeneration() call. -		 */ -		consoleFlush = new Runnable() { -			@Override -			public void run() { -				/*  -				 * Try to acquire printlock - wait here until jcgpService relinquishes it -				 * by calling wait(). This means that it is finished with the current generation -				 * and will wait for the console to be flushed to move on. -				 * It might be the case that the service has already released the lock by waiting -				 * on it; it makes no difference. In that case this will acquire the lock -				 * immediately and proceed to flush the console. -				 */ -				synchronized(printLock) { -					/* -					 * The lock is acquired, at this point we are certain that jcgpService -					 * cannot execute; it is currently waiting to be notified about the lock. -					 * No additional consoleFlush tasks can be scheduled with runLater() because -					 * the service is waiting. We can now take our time to flush the console. -					 */ -					console.flush(); -					/* -					 * Once the console finishes flushing, we notify jcgpService to perform the -					 * next generation. -					 */ -					printLock.notifyAll(); -				} -			} -		}; -		 -		/*  -		 * This service runs on a separate thread and performs -		 * the experiment, including console prints, in a thread-safe -		 * way. It is synchronized with consoleFlush. -		 */ -		jcgpService = new Service<Void> () { -			@Override -			protected Task<Void> createTask() { -				Task<Void> t = new Task<Void>() { -					@Override -					protected Void call() throws Exception { -						/* -						 * Only execute if the experiment isn't finished -						 * and the service hasn't been cancelled. -						 */ -						while (!isCancelled() && !jcgp.isFinished()) { -							/* -							 * Attempt to acquire the printlock. -							 * Successfully doing so means no printing -							 * is currently taking place and we are free -							 * to schedule a print task. -							 * This lock acquisition should never block. It should -							 * not be possible to execute this statement without -							 * having been notified by consoleFlush. -							 */ -							synchronized (printLock) { -								/* -								 * Lock has been acquired, schedule a print -								 * task ahead of time. The actual print messages -								 * haven't been send to the console yet, that happens -								 * during nextGeneration(), but since we have the lock -								 * consoleFlush() will sit and wait for us to release it -								 * whenever we are finished queueing prints. -								 */ -								Platform.runLater(consoleFlush); -								/* -								 * Perform the actual generation. Here zero or more -								 * strings might be sent to the console buffer. -								 */ -								jcgp.nextGeneration(); -								/* -								 * The generation is complete, relinquish the lock. -								 * By this point chances are the platform is already trying -								 * to execute the consoleFlush task that we scheduled. If it -								 * hasn't already started though, it doesn't matter; we will -								 * wait for a notification on the lock, which will only come -								 * when printing is complete. -								 */ -								printLock.wait(); -								/* -								 * We have been notified. This means all buffered messages have -								 * been successfully flushed to the actual console control and -								 * we are now ready to perform another generation (or break out -								 * of the loop if the loop conditions are no longer met). -								 */ -							} -							/* -							 * We no longer own the lock, but neither does consoleFlush.  -							 * The synchrony cycle has returned to its initial state, and we -							 * are free to acquire the lock again. -							 */ -						} -						/* -						 * Something happened to break the while loop - -						 * either the experiment finished or the user pressed -						 * pause. -						 */ -						if (jcgp.isFinished()) { -							// the experiment has finished, switch to pause mode -							Platform.runLater(new Runnable() { -								@Override -								public void run() { -									runningMode(false); -								} -							}); -						} -						return null; -					} -				}; -				return t; -			} -		}; -	} -	 -	@Override -	public void start(Stage primaryStage) throws Exception { -		/* -		 * This method gets called when the application launches. Once it -		 * returns, the application falls into the main loop which handles  -		 * events, so all elements must be constructed here. -		 */ -		 -		// make the console and set it so it is used for JCGP prints -		console = new ConsolePane(); -		jcgp.setConsole(console); -		 -		// store reference to the stage -		stage = primaryStage; - -		/* -		 * The experiment layer contains all of the experiment-related panes.  -		 * The only element that sits higher than this is the function selector. -		 */ -		BorderPane experimentLayer = new BorderPane(); -		/* -		 * The left frame encapsulates the population pane and the console. -		 * It goes into the center position of the experiment layer, next to the settings pane. -		 */ -		BorderPane leftFrame = new BorderPane(); -		 -		/* -		 * The population pane is a TabPane containing a tab for each chromosome.  -		 */ -		populationPane = new PopulationPane(this); -		 -		/* -		 * The settings pane is a big class containing the entire control pane -		 */ -		settingsPane = new SettingsPane(this); -		 -		// make control pane and console resizable -		HorizontalDragResize.makeDragResizable(settingsPane); -		VerticalDragResize.makeDragResizable(console); -		// prevent resizables from growing larger than the experiment layer -		settingsPane.maxWidthProperty().bind(experimentLayer.widthProperty()); -		console.maxHeightProperty().bind(experimentLayer.heightProperty()); - -		// put console and population pane in the main frame -		leftFrame.setCenter(populationPane); -		leftFrame.setBottom(console); -		 -		// set the main frame and the control pane in the experiment layer -		experimentLayer.setCenter(leftFrame); -		experimentLayer.setRight(settingsPane); -		 -		/* -		 * Now we deal with the stage. -		 */ -		primaryStage.setTitle("JCGP"); -		 -		// this pane holds the entire scene, that is its sole job. -		Pane sceneParent = new Pane(); -		// the experiment layer should fill the entire scene parent -		experimentLayer.prefHeightProperty().bind(sceneParent.heightProperty()); -		experimentLayer.prefWidthProperty().bind(sceneParent.widthProperty()); -		// the function selector goes over the experiment layer so it doesn't get covered by other panes -		sceneParent.getChildren().addAll(experimentLayer, functionSelector); -		 -		// set the scene, minimum sizes, show -		primaryStage.setScene(new Scene(sceneParent)); -		primaryStage.setMinWidth(800); -		primaryStage.setMinHeight(600); -		primaryStage.show(); -		 -		// when the main stage closes, close the test case table as well -		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { -			@Override -			public void handle(WindowEvent event) { -				if (settingsPane.getTestCaseTable() != null) { -					settingsPane.getTestCaseTable().close(); -				} -			} -		}); -	} - -	/** -	 * Run/pause method. -	 * Run the experiment if it is paused, or pause it if it is running. -	 * <br> -	 * This method is the callback used by the run/pause button. It -	 * controls the jcgp service. -	 */ -	public void runPause() { -		// do nothing if experiment is finished or parameters aren't valid -		if (!jcgp.isFinished() && settingsPane.areParametersValid()) { -			if (!running) { -				runningMode(true); -				jcgpService.restart(); -			} else { -				jcgpService.cancel(); -				runningMode(false); -			} -		} -	} -	 -	/** -	 * Perform a single generation using {@code nextGeneration()}.  -	 * <br> -	 * On top of that, this method performs all of the housekeeping  -	 * that is normally done before and after running, such as  -	 * refreshing the chromosome panes. -	 */ -	public void step() { -		// do nothing if experiment is finished, running or parameters aren't valid -		if (!running && !jcgp.isFinished() && settingsPane.areParametersValid()) { -			if (settingsPane.isResetRequired()) { -				reset(); -			} -			jcgp.nextGeneration(); -			console.flush(); -			 -			populationPane.updateGenes(); -			settingsPane.revalidateParameters(); -			settingsPane.updateControls(false, jcgp.isFinished()); -		} -	} -	 -	/** -	 * Reset button callback. If the parameters are valid,  -	 * this resets the entire experiment by calling {@code reset()} -	 * on jcgp. -	 */ -	public void reset() { -		if (!running && settingsPane.areParametersValid()) { -			setEvaluating(false); -			jcgp.reset(); -			settingsPane.applyParameters(); -			reDraw(); -		} -	} -	 -	/** -	 * Does a complete GUI refresh.  -	 * This is potentially lengthy, so use with care. -	 */ -	public void reDraw() { -		populationPane.remakeTabs(); -		settingsPane.revalidateParameters(); -		settingsPane.updateControls(false, jcgp.isFinished()); -		console.flush(); -	} -	 -	/** -	 * Toggles the entire GUI between run and pause -	 * mode.  -	 * <br><br> -	 * A lot of the GUI must be enabled or disabled -	 * depending on what the experiment is doing. This -	 * method provides a one-line way to make -	 * all required adjustments. -	 *  -	 * @param value true if experiment is running, false otherwise. -	 */ -	private void runningMode(boolean value) {		 -		if (value) { -			if (settingsPane.isResetRequired()) { -				reset(); -			} -		} else { -			populationPane.updateGenes(); -			settingsPane.revalidateParameters(); -		} -		populationPane.setDisable(value); -		settingsPane.updateControls(value, jcgp.isFinished()); -		 -		running = value; -	} -	 -	/** -	 * Refresh the function selector, used when functions are enabled or disabled. -	 */ -	public void updateFunctionSelector() { -		functionSelector.remakeFunctions(jcgp.getResources().getFunctionSet()); -	} -	 -	/** -	 * @return true if jcgp is evolving. -	 */ -	public boolean isWorking() { -		return running; -	} - -	/** -	 * Relocate the function selector to the right position -	 * relative to the specified node and set it visible. -	 *  -	 * @param event the mouse event containing cursor coordinates. -	 * @param node the node whose function should be changed. -	 */ -	public void bringFunctionSelector(MouseEvent event, GUINode node) { -		functionSelector.relocateAndShow(event, node); -	} - -	/** -	 * @return a reference to the {@code JCGP} experiment. -	 */ -	public JCGP getExperiment() { -		return jcgp; -	} -	 -	/** -	 * Starts the evaluation process with the given test case. -	 * It does so by calling {@code evaluateTestCase()} on -	 * the population pane. -	 *  -	 * @param testCase the test case to evaluate. -	 */ -	public void evaluateTestCase(TestCase<Object> testCase) { -		populationPane.evaluateTestCase(testCase); -	} - -	/** -	 * Hide all evaluated values. This should be called when -	 * evaluations are no longer being performed. -	 */ -	public void hideGeneValues() { -		populationPane.hideValues(); -	} - -	/** -	 * Set the system into evaluation mode.  -	 * When in evaluation mode, the population pane -	 * refreshes the node values whenever connection -	 * changes happen. -	 *  -	 * @param value true if evaluations are happening, false otherwise. -	 */ -	public void setEvaluating(boolean value) { -		populationPane.setEvaluating(value); -	} - -	/** -	 * @return a reference to the GUI stage. -	 */ -	public Stage getStage() { -		return stage; -	} -	 -	/** -	 * Writes all buffered content out to the GUI console. -	 */ -	public void flushConsole() { -		console.flush(); -	} - -	/** -	 * @return the index of the chromosome currently being looked at. -	 */ -	public int getChromosomeIndex() { -		return populationPane.getSelectionModel().getSelectedIndex(); -	} -} diff --git a/src/jcgp/gui/console/ConsolePane.java b/src/jcgp/gui/console/ConsolePane.java deleted file mode 100644 index de193a5..0000000 --- a/src/jcgp/gui/console/ConsolePane.java +++ /dev/null @@ -1,122 +0,0 @@ -package jcgp.gui.console; - -import javafx.event.ActionEvent; -import javafx.event.Event; -import javafx.event.EventDispatchChain; -import javafx.event.EventDispatcher; -import javafx.event.EventHandler; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.TextArea; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.AnchorPane; -import jcgp.backend.resources.Console; -import jcgp.gui.constants.Constants; - -/** - * Console pane used by the GUI to display CGP output messages. - * This class realises {@code Console}. It consists of a JavaFX - * {@code TextArea} and a {@code StringBuffer}. The buffer is filled - * as print messages are queued. Calling {@code flush()} writes the - * contents of the buffer to the {@code TextArea} and empties the buffer. - *  - * @see Console - * @author Eduardo Pedroni - * - */ -public class ConsolePane extends AnchorPane implements Console { -	 -	private TextArea textArea = new TextArea("Welcome to JCGP!\n"); -	private StringBuffer printBuffer = new StringBuffer(); -		 -	/** -	 * Creates a new instance of this class. -	 */ -	public ConsolePane() { -		super(); -		textArea.setEditable(false); -		/* -		 * This nasty hack is needed because the default TextArea ContextMenu is not -		 * in the public API, making it impossible to override it with a custom one. -		 * This has not been fixed as of 8/4/2014. -		 *  -		 * The following code modifies the EventDispatcher to consume the right mouse -		 * button click, preventing the default menu from appearing. It propagates the mouse -		 * click further so other elements will respond appropriately. -		 *  -		 * TODO this should be refactored once the API is updated. -		 */ -		final EventDispatcher initial = textArea.getEventDispatcher(); -		textArea.setEventDispatcher(new EventDispatcher() { -			@Override -			public Event dispatchEvent(Event event, EventDispatchChain tail) { -				if (event instanceof MouseEvent) { -					MouseEvent mouseEvent = (MouseEvent)event; -					if (mouseEvent.getButton() == MouseButton.SECONDARY ||  -							(mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.isControlDown())) { -						event.consume(); -					} -				} -				return initial.dispatchEvent(event, tail); -			} -		}); -		 -		// make the new context menu including the clear option		 -		MenuItem copySelected = new MenuItem("Copy"); -		copySelected.setOnAction(new EventHandler<ActionEvent>() {	 -			@Override -			public void handle(ActionEvent event) { -				textArea.copy(); -			} -		}); -		MenuItem selectAll = new MenuItem("Select all"); -		selectAll.setOnAction(new EventHandler<ActionEvent>() {	 -			@Override -			public void handle(ActionEvent event) { -				textArea.selectAll(); -			} -		}); -		MenuItem clearConsole = new MenuItem("Clear"); -		clearConsole.setOnAction(new EventHandler<ActionEvent>() {	 -			@Override -			public void handle(ActionEvent event) { -				textArea.setText(""); -			} -		}); -				 -		textArea.setContextMenu(new ContextMenu(copySelected, -												selectAll,  -												new SeparatorMenuItem(), -												clearConsole)); -		 -		// anchor the text area so it resizes automatically -		AnchorPane.setTopAnchor(textArea, Constants.RESIZE_MARGIN); -		AnchorPane.setBottomAnchor(textArea, 0.0); -		AnchorPane.setRightAnchor(textArea, 0.0); -		AnchorPane.setLeftAnchor(textArea, 0.0); -		 -		setMinHeight(Constants.CONSOLE_MIN_HEIGHT); -		setPrefHeight(Constants.CONSOLE_MIN_HEIGHT); -		 -		getChildren().add(textArea); -	} - -	@Override -	public void println(String s) { -		printBuffer.append(s + "\n"); -	} - -	@Override -	public void print(String s) { -		printBuffer.append(s); -	} - -	@Override -	public void flush() { -		textArea.appendText(printBuffer.toString()); -		printBuffer = new StringBuffer(); -	} -	 -} diff --git a/src/jcgp/gui/constants/Constants.java b/src/jcgp/gui/constants/Constants.java deleted file mode 100644 index 509d982..0000000 --- a/src/jcgp/gui/constants/Constants.java +++ /dev/null @@ -1,170 +0,0 @@ -package jcgp.gui.constants; - -import javafx.scene.paint.Paint; - -/** - * Holds the constants used in the GUI. - *  - * @author Eduardo Pedroni - * - */ -public final class Constants { - -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private Constants(){} -	 -	/*--------------------------------------------------------------------------------------------------- -	 * Colour Strings  -	 *-------------------------------------------------------------------------------------------------*/ -	/** -	 * A {@code String} containing the colour used for representing neutrality. -	 */ -	public static final String NEUTRAL_COLOUR = "#FFFFFF"; -	/** -	 * A {@code String} containing the hexadecimal colour used for representing a hard highlight. -	 * A "hard" select, for instance, happens when an output path is locked on the chromosome pane. -	 */ -	public static final String HARD_HIGHLIGHT_COLOUR = "#5496FF"; -	/** -	 * A {@code String} containing the hexadecimal colour used for a medium highlight. -	 * One example of such a selection is the colour applied to a node when it is hovered over. -	 */ -	public static final String MEDIUM_HIGHLIGHT_COLOUR = "#75BAFF"; -	/** -	 * A {@code String} containing the hexadecimal colour used for a soft highlight. -	 * When hovering over a node, its connections are soft-selected. -	 */ -	public static final String SOFT_HIGHLIGHT_COLOUR = "#C7DFFF"; -	/** -	 * A {@code String} containing the hexadecimal colour used for representing a good selection. -	 * Ideally a shade of green, used for instance when a manual connection is valid. -	 */ -	public static final String GOOD_SELECTION_COLOUR = "#38C25B"; -	/** -	 * A {@code String} containing the hexadecimal colour used for representing a neutral selection. -	 * Ideally a shade of yellow, used for instance when a manual connection is already the current connection. -	 */ -	public static final String NEUTRAL_SELECTION_COLOUR = "#FFEF73"; -	/** -	 * A {@code String} containing the hexadecimal colour used for representing a bad selection. -	 * Ideally a shade of red, use for instance when a manual connection is not valid. -	 */ -	public static final String BAD_SELECTION_COLOUR = "#FF5C5C"; -	/** -	 * A {@code String} containing the hexadecimal colour used for the gene sockets. -	 */ -	public static final String SOCKET_COLOUR = "#FFFFFF"; -	 -	/*--------------------------------------------------------------------------------------------------- -	 * Colour Paints  -	 *-------------------------------------------------------------------------------------------------*/ -	/** -	 * A {@code Paint} containing the colour used for representing neutrality. -	 */ -	public static final Paint NEUTRAL_PAINT = Paint.valueOf(NEUTRAL_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for representing a hard highlight. -	 * A "hard" select, for instance, happens when an output path is locked on the chromosome pane. -	 */ -	public static final Paint HARD_HIGHLIGHT_PAINT = Paint.valueOf(HARD_HIGHLIGHT_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for a medium highlight. -	 * One example of such a selection is the colour applied to a node when it is hovered over. -	 */ -	public static final Paint MEDIUM_HIGHLIGHT_PAINT = Paint.valueOf(MEDIUM_HIGHLIGHT_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for a soft highlight. -	 * When hovering over a node, its connections are soft-selected. -	 */ -	public static final Paint SOFT_HIGHLIGHT_PAINT = Paint.valueOf(SOFT_HIGHLIGHT_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for representing a good selection. -	 * Ideally a shade of green, used for instance when a manual connection is valid. -	 */ -	public static final Paint GOOD_SELECTION_PAINT = Paint.valueOf(GOOD_SELECTION_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for representing a neutral selection. -	 * Ideally a shade of yellow, used for instance when a manual connection is already the current connection. -	 */ -	public static final Paint NEUTRAL_SELECTION_PAINT = Paint.valueOf(NEUTRAL_SELECTION_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for representing a bad selection. -	 * Ideally a shade of red, use for instance when a manual connection is not valid. -	 */ -	public static final Paint BAD_SELECTION_PAINT = Paint.valueOf(BAD_SELECTION_COLOUR); -	/** -	 * A {@code Paint} containing the colour used for the gene sockets. -	 */ -	public static final Paint SOCKET_PAINT = Paint.valueOf(SOCKET_COLOUR); -	 -	/*--------------------------------------------------------------------------------------------------- -	 * Sizes and distances  -	 *-------------------------------------------------------------------------------------------------*/ -	/** -	 * The width or height of the area that can be clicked on -	 * to drag-resize a pane. -	 */ -    public static final double RESIZE_MARGIN = 5.0; -    /** -	 * The minimum width of the settings pane, to prevent it -	 * from being resized beyond visibility. -	 */ -    public static final double SETTINGS_MIN_WIDTH = 200; -    /** -	 * The minimum width of the console pane, to prevent it -	 * from being resized beyond visibility. -	 */ -    public static final double CONSOLE_MIN_HEIGHT = 100; -    /** -     * Radius used for the representation of nodes in the grid. -     */ -    public static final double NODE_RADIUS = 35; -	/** -	 * Spacing between each node. -	 */ -	public static final double SPACING = 15; -	/** -	 * The margin between the genes and the edge of the chromosome pane. -	 */ -	public static final double CHROMOSOME_PANE_MARGIN = 10; -	/** -	 * The angle across which the node's sockets are evenly distributed. -	 */ -	public static final double THETA = Math.PI / 1.4; -	/** -	 * The radius of the connection sockets, calculated as a function of NODE_RADIUS. -	 */ -	public static final double SOCKET_RADIUS = Math.sqrt(NODE_RADIUS) / 1.8; -	/** -	 * Size of the text in each node. -	 */ -	public static final double NODE_TEXT = NODE_RADIUS / 2.5; -	 -	/*--------------------------------------------------------------------------------------------------- -	 * CSS Styles -	 * TODO extract to stylesheet? -	 *-------------------------------------------------------------------------------------------------*/ -	/** -	 * The basic style of text boxes used in parameters. -	 */ -	public static final String BASE_TEXT_STYLE = "-fx-border-color: #C9C9C9; -fx-border-radius: 2; -fx-padding: 0; "; -	/** -	 * The basic style of check boxes used in parameters. -	 */ -	public static final String BASE_CHECKBOX_STYLE = "-fx-padding: 0; "; -	/** -	 * The style applied to invalid parameters, using BAD_SELECTION_COLOUR. -	 */ -	public static final String INVALID_PARAMETER_STYLE = "-fx-background-color: " + BAD_SELECTION_COLOUR; -	/** -	 * The style applied to neutral parameters, using NEUTRAL_SELECTION_COLOUR. -	 */ -	public static final String WARNING_PARAMETER_STYLE = "-fx-background-color: " + NEUTRAL_SELECTION_COLOUR; -	/** -	 * The style applied to valid parameters, using NEUTRAL_COLOUR. -	 */ -	public static final String VALID_PARAMETER_STYLE = "-fx-background-color: " + NEUTRAL_COLOUR;	 -     -} diff --git a/src/jcgp/gui/constants/Position.java b/src/jcgp/gui/constants/Position.java deleted file mode 100644 index 6d4e02b..0000000 --- a/src/jcgp/gui/constants/Position.java +++ /dev/null @@ -1,103 +0,0 @@ -package jcgp.gui.constants; - -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import jcgp.gui.GUI; -import jcgp.gui.population.GUIGene; -import jcgp.gui.population.GUIInput; -import jcgp.gui.population.GUINode; -import jcgp.gui.population.GUIOutput; - -/** - * Abstracts the task of positioning GUI components. - * <br> - * Do not instantiate this class; instead, use the {@code public static} methods provided. - *  - * @author Eduardo Pedroni - * - */ -public final class Position { -	 -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private Position() {} -	 -	/** -	 * Sets the X and Y layouts of the specified input to the appropriate values, according to its index. -	 *  -	 * @param input the {@code GUIInput} instance to relocate. -	 */ -	public static void place(GUIInput input) { -		// inputs are the first column, so we only worry about the margin and their index -		input.relocate(Constants.CHROMOSOME_PANE_MARGIN, -				input.getInput().getIndex() * (2 * Constants.NODE_RADIUS + Constants.SPACING) + Constants.CHROMOSOME_PANE_MARGIN); -	} -	 -	/** -	 * Sets the X and Y layouts of the specified node to the appropriate values, according to its row and column values. -	 * This also connects the start of every line with its respective socket. Therefore, this method should be called at least -	 * once when the {@code GUINode} is instantiated. -	 *  -	 * @param node the {@code GUINode} instance to relocate. -	 */ -	public static void place(GUINode node) { -		// calculate x and y offsets, in relation to the layout origin -		double xOffset = (node.getNode().getColumn() + 1) * (2 * Constants.NODE_RADIUS + Constants.SPACING) + Constants.CHROMOSOME_PANE_MARGIN; -		double yOffset = node.getNode().getRow() * (2 * Constants.NODE_RADIUS + Constants.SPACING) + Constants.CHROMOSOME_PANE_MARGIN; -		 -		// move node -		node.relocate(xOffset, yOffset); -		 -		// use the offset and the socket positions to connect the lines -		for (int i = 0; i < GUI.resources.arity(); i++) { -			node.getLines()[i].setStartX(node.getSocket(i).getCenterX() + xOffset + Constants.NODE_RADIUS + Constants.SOCKET_RADIUS); -			node.getLines()[i].setStartY(node.getSocket(i).getCenterY() + yOffset + Constants.NODE_RADIUS); -		} -	} -	 -	/** -	 * Sets the X and Y layouts of the specified output to the appropriate values, according to its index. -	 * This also connects the start of the output's single line to its single input socket.Therefore, -	 * this method should be called at least once when the {@code GUIOutput} is instantiated. -	 *  -	 * @param output the {@code GUIOutput} instance to relocate. -	 */ -	public static void place(GUIOutput output) { -		// the output's position is a function of the number of columns and its own index -		output.relocate(((GUI.resources.columns() + 1) * (2 * Constants.NODE_RADIUS + Constants.SPACING)) + Constants.CHROMOSOME_PANE_MARGIN, -				output.getOutput().getIndex() * (2 * Constants.NODE_RADIUS + Constants.SPACING) + Constants.CHROMOSOME_PANE_MARGIN); -		output.getLines()[0].setStartX(output.getLayoutX() - Constants.NODE_RADIUS); -		output.getLines()[0].setStartY(output.getLayoutY()); -	} -	 -	/** -	 * Connects the end of a specified line to the specified gene. -	 *  -	 * @param line the line to connect. -	 * @param target the target gene to connect to. -	 */ -	public static void connect(Line line, GUIGene target) { -		// set line ends based on the layout position of the target -		line.setEndX(target.getLayoutX() + Constants.NODE_RADIUS); -		line.setEndY(target.getLayoutY()); -	} - -	/** -	 * Relocates the given socket to the appropriate position given the  -	 * socket's index. -	 *  -	 * @param index the socket index. -	 * @param socket the {@code Circle} instance to relocate. -	 */ -	public static void placeSocket(int index, Circle socket) { -		// calculate the angle with respect to the x-axis -		double angle = (((index + 1) / ((double) (GUI.resources.arity() + 1))) * Constants.THETA) - (Constants.THETA / 2); -		// convert to cartesian form -		double xPos = -Math.cos(angle) * Constants.NODE_RADIUS; -		double yPos = Math.sin(angle) * Constants.NODE_RADIUS; -		// set centre -		socket.setCenterX(xPos); -		socket.setCenterY(yPos); -	} -} diff --git a/src/jcgp/gui/dragresize/HorizontalDragResize.java b/src/jcgp/gui/dragresize/HorizontalDragResize.java deleted file mode 100644 index e88eafd..0000000 --- a/src/jcgp/gui/dragresize/HorizontalDragResize.java +++ /dev/null @@ -1,131 +0,0 @@ -package jcgp.gui.dragresize; - -import javafx.event.EventHandler; -import javafx.scene.Cursor; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import jcgp.gui.constants.Constants; - -/** - * This class adds horizontal drag resize functionality to any  - * arbitrary region provided. This is done by using the static - * method {@code makeDragResizable()}. - * <br><br> - * This is based on a class by Andrew Till found on: - * http://andrewtill.blogspot.co.uk/2012/12/dragging-to-resize-javafx-region.html - *  - */ -public class HorizontalDragResize { -	 -	private boolean dragging = false; -	private final Region region; -	 -	/** -	 * For internal use only, creates an instance of the actual -	 * resizer used. -	 *  -	 * @param region the region to make resizable. -	 */ -	private HorizontalDragResize(Region region) { -		this.region = region; -	} -	 -	/** -	 * Makes the specified region drag resizable. -	 * This particular implementation only creates a resize  -	 * click-and-drag area on the left side of the region.  -	 * The resize area is defined by {@code GUI.RESIZE_MARGIN}. -	 *  -	 * @param region the region to make resizable. -	 */ -	public static void makeDragResizable(final Region region) { -		// make the instance, this actually performs the resizing -		final HorizontalDragResize dr = new HorizontalDragResize(region); - -		// set mouse listeners -		region.setOnMousePressed(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -		        dr.mousePressed(event); -			} -		}); -		region.setOnMouseDragged(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseDragged(event); -			} -		}); -		region.setOnMouseMoved(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseMoved(event); -			} -		}); -		region.setOnMouseReleased(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseReleased(); -			} -		}); -		 -	} -	 -	/** -	 * If the press happened in the resize area, raise the drag flag. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mousePressed(MouseEvent event) { -		if(isInDraggableZone(event)) { -	        dragging = true; -        } -	} - -	/** -	 * If drag flag is high, resize the region to match the mouse position. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mouseDragged(MouseEvent event) { -		if(dragging) { -			double newWidth = region.getWidth() - event.getX(); -			if (newWidth >= region.getMinWidth()) { -				region.setPrefWidth(newWidth); -			} else { -				region.setPrefWidth(region.getMinWidth()); -			} -		} -	} -	 -	/** -	 * Change the cursor if the mouse position overlaps with the resize area. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mouseMoved(MouseEvent event) { -		if(isInDraggableZone(event) || dragging) { -			region.setCursor(Cursor.H_RESIZE); -		} else { -			region.setCursor(Cursor.DEFAULT); -		} -	} - -	/** -	 * Finish resizing. -	 */ -	private void mouseReleased() { -		dragging = false; -		region.setCursor(Cursor.DEFAULT); -	} - -	/** -	 * Assert whether the mouse cursor is in the draggable area defined by {@code GUI.RESIZE_MARGIN}. -	 *  -	 * @param event the associated mouse event. -	 * @return true if the mouse position is in the draggable area. -	 */ -	private boolean isInDraggableZone(MouseEvent event) { -		return event.getX() < (Constants.RESIZE_MARGIN); -	} - -} diff --git a/src/jcgp/gui/dragresize/VerticalDragResize.java b/src/jcgp/gui/dragresize/VerticalDragResize.java deleted file mode 100644 index 4f784e5..0000000 --- a/src/jcgp/gui/dragresize/VerticalDragResize.java +++ /dev/null @@ -1,132 +0,0 @@ -package jcgp.gui.dragresize; - -import javafx.event.EventHandler; -import javafx.scene.Cursor; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Region; -import jcgp.gui.constants.Constants; - -/** - * This class adds vertical drag resize functionality to any  - * arbitrary region provided. This is done by using the static - * method {@code makeDragResizable()}. - * <br><br> - * This is based on a class by Andrew Till found on: - * http://andrewtill.blogspot.co.uk/2012/12/dragging-to-resize-javafx-region.html - *  - */ -public class VerticalDragResize { -	 -	private boolean dragging = false; -	private final Region region; -	 -	/** -	 * For internal use only, creates an instance of the actual -	 * resizer used. -	 *  -	 * @param region the region to make resizable. -	 */ -	private VerticalDragResize(Region region) { -		this.region = region; -	} -	 -	/** -	 * Makes the specified region drag resizable. -	 * This particular implementation only creates a resize  -	 * click-and-drag area on the top side of the region.  -	 * The resize area is defined by {@code GUI.RESIZE_MARGIN}. -	 *  -	 * @param region the region to make resizable. -	 */ -	public static void makeDragResizable(final Region region) { -		// make the instance, this actually performs the resizing -		final VerticalDragResize dr = new VerticalDragResize(region); - -		// set mouse listeners -		region.setOnMousePressed(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -		        dr.mousePressed(event); -			} -		}); -		region.setOnMouseDragged(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseDragged(event); -			} -		}); -		region.setOnMouseMoved(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseMoved(event); -			} -		}); -		region.setOnMouseReleased(new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dr.mouseReleased(); -			} -		}); -		 -	} -	 -	/** -	 * If the press happened in the resize area, raise the drag flag. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mousePressed(MouseEvent event) { -		if(isInDraggableZone(event)) { -	        dragging = true; -        } -	} - -	/** -	 * If drag flag is high, resize the region to match the mouse position. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mouseDragged(MouseEvent event) { -		if(dragging) { -			double newHeight = region.getHeight() - event.getY(); -			if (newHeight >= region.getMinHeight()) { -				region.setPrefHeight(newHeight); -			} else { -				region.setPrefHeight(region.getMinHeight()); -			} -		} -	} -	 -	/** -	 * Change the cursor if the mouse position overlaps with the resize area. -	 *  -	 * @param event the associated mouse event. -	 */ -	private void mouseMoved(MouseEvent event) { -		if(isInDraggableZone(event) || dragging) { -			region.setCursor(Cursor.V_RESIZE); -        } -        else { -        	region.setCursor(Cursor.DEFAULT); -        } -	} - -	/** -	 * Finish resizing. -	 */ -	private void mouseReleased() { -		dragging = false; -		region.setCursor(Cursor.DEFAULT); -	} - -	/** -	 * Assert whether the mouse cursor is in the draggable area defined by {@code GUI.RESIZE_MARGIN}. -	 *  -	 * @param event the associated mouse event. -	 * @return true if the mouse position is in the draggable area. -	 */ -	private boolean isInDraggableZone(MouseEvent event) { -		return event.getY() < (Constants.RESIZE_MARGIN); -	} - -} diff --git a/src/jcgp/gui/handlers/InputHandlers.java b/src/jcgp/gui/handlers/InputHandlers.java deleted file mode 100644 index cc677eb..0000000 --- a/src/jcgp/gui/handlers/InputHandlers.java +++ /dev/null @@ -1,56 +0,0 @@ -package jcgp.gui.handlers; - -import javafx.event.EventHandler; -import javafx.scene.input.MouseEvent; -import jcgp.gui.population.GUIGene.GUIGeneState; -import jcgp.gui.population.GUIInput; - -/** - * Holds the handlers that define the behaviour of {@code GUIInput}. - * <br><br> - * The handlers are instantiated here statically and added to {@code GUIInput} - * instances using {@code InputHandlers.addHandlers(...)}. This guarantees that - * all inputs behave the same way without instantiating a new set of handlers for - * each input instance. - *  - * @author Eduardo Pedroni - * - */ -public final class InputHandlers { -	 -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private InputHandlers() {} - -	/** -	 * Inputs don't do much; set state to hover when mouse enters. -	 */ -	private static EventHandler<MouseEvent> mouseEnteredHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			((GUIInput) event.getSource()).setState(GUIGeneState.HOVER); -		} -	}; -	 -	/** -	 * Inputs don't do much; set state to neutral when mouse exits. -	 */ -	private static EventHandler<MouseEvent> mouseExitedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			((GUIInput) event.getSource()).setState(GUIGeneState.NEUTRAL); -		} -	}; -	 -	/** -	 * Adds all handlers to the specified input. -	 *  -	 * @param input the {@code GUIInput} to which the handlers will be added. -	 */ -	public static void addHandlers(GUIInput input) { -		input.addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEnteredHandler); -		input.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); -	} -	 -} diff --git a/src/jcgp/gui/handlers/NodeHandlers.java b/src/jcgp/gui/handlers/NodeHandlers.java deleted file mode 100644 index b413a62..0000000 --- a/src/jcgp/gui/handlers/NodeHandlers.java +++ /dev/null @@ -1,164 +0,0 @@ -package jcgp.gui.handlers; - -import javafx.event.EventHandler; -import javafx.scene.input.MouseDragEvent; -import javafx.scene.input.MouseEvent; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import jcgp.backend.population.Gene; -import jcgp.gui.GUI; -import jcgp.gui.constants.Position; -import jcgp.gui.population.ChromosomePane; -import jcgp.gui.population.GUIConnection; -import jcgp.gui.population.GUIGene; -import jcgp.gui.population.GUIGene.GUIGeneState; -import jcgp.gui.population.GUINode; - -/** - * Holds the handlers that define the behaviour of {@code GUINode}. - * <br><br> - * The handlers are instantiated here statically and added to {@code GUINode} - * instances using {@code NodeHandlers.addHandlers(...)}. This guarantees that - * all nodes behave the same way without instantiating a new set of handlers for - * each node instance. - *  - * @author Eduardo Pedroni - * - */ -public final class NodeHandlers { - -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private NodeHandlers() {} - -	/** -	 * Set the node to {@code GUIGeneState.HOVER} state, and set its immediate connections to {@code GUIGeneState.EXTENDED_HOVER}. -	 */ -	private static EventHandler<MouseEvent> mouseEnteredHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// acquire the source, we can safely cast it to GUINode -			GUINode source = (GUINode) event.getSource(); - -			source.setState(GUIGeneState.HOVER); -			for (int i = 0; i < GUI.resources.arity(); i++) { -				((GUIGene) ((Gene) source.getNode().getConnection(i)).getGUIObject()).setState(GUIGeneState.EXTENDED_HOVER); -			} -		} -	}; - -	/** -	 * Set the node and its immediate connections to {@code GUIGeneState.NEUTRAL} state. -	 */ -	private static EventHandler<MouseEvent> mouseExitedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// acquire the source, we can safely cast it to GUINode -			GUINode source = (GUINode) event.getSource(); - -			if (Target.getSourceMutable() != source) { -				source.setState(GUIGeneState.NEUTRAL); -				for (int i = 0; i < GUI.resources.arity(); i++) { -					((GUIGene) ((Gene) source.getNode().getConnection(i)).getGUIObject()).setState(GUIGeneState.NEUTRAL); -				} -			} -		} -	}; - -	private static EventHandler<MouseEvent> socketDragDetected = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// it's safe to assume that the source is the socket -			((GUINode) ((Circle) event.getSource()).getParent()).startFullDrag(); -		} -	}; - -	private static EventHandler<MouseEvent> socketMousePressedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// it's safe to assume that the source is the socket -			Target.start((Circle) event.getSource()); -		} -	}; - -	private static EventHandler<MouseEvent> socketMouseDraggedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// this can only happen after a press, so we know Target is up-to-date -			if (!Target.isProspecting()) { -				GUINode node = (GUINode) Target.getSourceMutable(); -				Line line = Target.getConnectionLine(); -				line.setEndX(event.getX() + node.getLayoutX()); -				line.setEndY(event.getY() + node.getLayoutY()); -			} - -		} -	}; - -	private static EventHandler<MouseEvent> socketMouseReleasedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { - -			GUINode node = (GUINode) ((Circle) event.getSource()).getParent(); -			int connectionId = Integer.valueOf(((Circle) event.getSource()).getId()); - -			Position.connect(node.getLines()[connectionId], (GUIGene) ((Gene) node.getNode().getConnection(connectionId)).getGUIObject()); -		} -	}; - -	private static EventHandler<MouseDragEvent> dragEnteredHandler = new EventHandler<MouseDragEvent>() { -		@Override -		public void handle(MouseDragEvent event) { -			// acquire the source, we can safely cast it to GUINode -			GUINode source = (GUINode) event.getSource(); -			if (Target.getCurrentConnection() == source) { -				source.setState(GUIGeneState.NEUTRAL_TARGET); -				// we are now prospecting -				Target.setProspecting(true); -				Position.connect(Target.getConnectionLine(), source); -			} else if (ChromosomePane.isAllowed(Target.getSourceMutable(), (GUIConnection) source)) { -				source.setState(GUIGeneState.GOOD_TARGET); -				// we are now prospecting -				Target.setProspecting(true); -				Position.connect(Target.getConnectionLine(), source); -			} else { -				source.setState(GUIGeneState.BAD_TARGET); -			} -		} -	}; - -	private static EventHandler<MouseDragEvent> dragExitedHandler = new EventHandler<MouseDragEvent>() { -		@Override -		public void handle(MouseDragEvent event) { -			// acquire the source, we can safely cast it to GUINode -			GUINode source = (GUINode) event.getSource(); -			source.setState(GUIGeneState.NEUTRAL); -			 -			// no longer prospecting -			Target.setProspecting(false); -		} -	}; - -	/** -	 * Adds all handlers to the specified node. -	 *  -	 * @param node the {@code GUINode} to which the handlers will be added. -	 */ -	public static void addHandlers(GUINode node) { -		node.addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEnteredHandler); -		node.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); - -		node.addEventHandler(MouseDragEvent.MOUSE_DRAG_ENTERED, dragEnteredHandler); -		node.addEventHandler(MouseDragEvent.MOUSE_DRAG_EXITED, dragExitedHandler); - -		Circle[] sockets = node.getSockets(); -		for (int s = 0; s < sockets.length; s++) { - -			sockets[s].addEventFilter(MouseEvent.DRAG_DETECTED, socketDragDetected); -			sockets[s].addEventHandler(MouseEvent.MOUSE_PRESSED, socketMousePressedHandler); -			sockets[s].addEventHandler(MouseEvent.MOUSE_DRAGGED, socketMouseDraggedHandler); -			sockets[s].addEventHandler(MouseEvent.MOUSE_RELEASED, socketMouseReleasedHandler); -		} -	} -} diff --git a/src/jcgp/gui/handlers/OutputHandlers.java b/src/jcgp/gui/handlers/OutputHandlers.java deleted file mode 100644 index b89d746..0000000 --- a/src/jcgp/gui/handlers/OutputHandlers.java +++ /dev/null @@ -1,84 +0,0 @@ -package jcgp.gui.handlers; - -import javafx.event.EventHandler; -import javafx.scene.input.MouseEvent; -import jcgp.backend.population.Gene; -import jcgp.gui.population.GUIConnection; -import jcgp.gui.population.GUIGene.GUIGeneState; -import jcgp.gui.population.GUIOutput; - -/** - * Holds the handlers that define the behaviour of {@code GUIOutput}. - * <br><br> - * The handlers are instantiated here statically and added to {@code GUIOutput} - * instances using {@code OutputHandlers.addHandlers(...)}. This guarantees that - * all outputs behave the same way without instantiating a new set of handlers for - * each output instance. - *  - * @author Eduardo Pedroni - * - */ -public final class OutputHandlers { -	 -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private OutputHandlers() {} - -	/** -	 * Set the output to {@code GUIGeneState.HOVER} state, and recursively set its active genes -	 * to {@code GUIGeneState.ACTIVE_HOVER}. -	 */ -	private static EventHandler<MouseEvent> mouseEnteredHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// acquire the source, we can safely cast it to GUIOutput -			GUIOutput source = (GUIOutput) event.getSource(); - -			source.setState(GUIGeneState.HOVER); -			((GUIConnection) ((Gene) source.getOutput().getSource()).getGUIObject()).setStateRecursively(GUIGeneState.ACTIVE_HOVER); -		} -	}; - -	/** -	 * Set the output and all of its active genes to {@code GUIGeneState.NEUTRAL} state. -	 */ -	private static EventHandler<MouseEvent> mouseExitedHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// acquire the source, we can safely cast it to GUIOutput -			GUIOutput source = (GUIOutput) event.getSource(); -			 -			source.setState(GUIGeneState.NEUTRAL); -			((GUIConnection) ((Gene) source.getOutput().getSource()).getGUIObject()).setStateRecursively(GUIGeneState.NEUTRAL); -		} -	}; - -	/** -	 * If the output is locked, unlock it and all of its associated genes recursively. -	 * If it is unlocked, lock it and its active genes. -	 */ -	private static EventHandler<MouseEvent> mouseClickHandler = new EventHandler<MouseEvent>() { -		@Override -		public void handle(MouseEvent event) { -			// acquire the source, we can safely cast it to GUIOutput -			GUIOutput source = (GUIOutput) event.getSource(); - -			boolean lock = !source.isLocked(); -			source.setLock(lock); -			((GUIConnection) ((Gene) source.getOutput().getSource()).getGUIObject()).setLockRecursively(lock); -		} -	}; - -	/** -	 * Adds all handlers to the specified output. -	 *  -	 * @param output the {@code GUIOutput} to which the handlers will be added. -	 */ -	public static void addHandlers(GUIOutput output) { -		output.addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEnteredHandler); -		output.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); -		output.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickHandler); -	} - -} diff --git a/src/jcgp/gui/handlers/Target.java b/src/jcgp/gui/handlers/Target.java deleted file mode 100644 index b050663..0000000 --- a/src/jcgp/gui/handlers/Target.java +++ /dev/null @@ -1,70 +0,0 @@ -package jcgp.gui.handlers; - -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import jcgp.gui.population.GUIConnection; -import jcgp.gui.population.GUIMutable; - -/** - * @author Eduardo Pedroni - * - */ -public final class Target { - -	/** -	 * Private constructor to prevent instantiation. -	 */ -	private Target() {} -	 -	private static GUIConnection targetConnection; -	private static GUIMutable sourceMutable; -	private static int connectionIndex; -	private static Line connectionLine; -	private static Circle sourceSocket; -	private static boolean prospecting = false; -	 -	public static void start(Circle newSocket) { -		// store new socket -		sourceSocket = newSocket; -		// derive the rest of the information from it -		connectionIndex = Integer.valueOf(newSocket.getId()); -		sourceMutable = (GUIMutable) newSocket.getParent(); -		connectionLine = sourceMutable.getLines()[connectionIndex]; -	} -	 -	public static GUIMutable getSourceMutable() { -		return sourceMutable; -	} -	 -	public static int getConnectionIndex() { -		return connectionIndex; -	} -	 -	public static Line getConnectionLine() { -		return connectionLine; -	} -	 -	public static Circle getSourceSocket() { -		return sourceSocket; -	} -	 -	public static GUIConnection getTarget() { -		return targetConnection; -	} -	 -	public static GUIConnection getCurrentConnection() { -		return sourceMutable.getConnections()[connectionIndex]; -	} -	 -	public static void setProspecting(boolean value) { -		prospecting = value; -	} -	 -	public static boolean isProspecting() { -		return prospecting; -	} -	 -	public static void setTarget(GUIConnection newTarget) { -		targetConnection = newTarget; -	} -} diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java deleted file mode 100644 index a87a054..0000000 --- a/src/jcgp/gui/population/ChromosomePane.java +++ /dev/null @@ -1,140 +0,0 @@ -package jcgp.gui.population; - -import java.util.ArrayList; - -import javafx.scene.control.ScrollPane; -import javafx.scene.layout.Pane; -import javafx.scene.shape.Line; -import jcgp.backend.population.Chromosome; -import jcgp.backend.population.Node; -import jcgp.gui.GUI; - -/** - * This extension of {@code ScrollPane} contains a series of - * nodes, inputs and outputs spread across a grid. It also contains - * all of the connection lines laid over the nodes, inputs and outputs. - *  - *  - * @author Eduardo Pedroni - * - */ -public class ChromosomePane extends ScrollPane { - -	private GUIInput[] guiInputs; -	private GUINode[][] guiNodes; -	private GUIOutput[] guiOutputs; - -	private Pane content; - -	private boolean target = false; - -	public ChromosomePane(Chromosome chromosome) { -		super(); - -		ArrayList<Line> connectionLines = new ArrayList<Line>(); - -		int rows = GUI.resources.rows(); -		int columns = GUI.resources.columns(); - -		content = new Pane(); -		content.setId("content pane for genes"); - -		/*  -		 * inputs -		 */ -		guiInputs = new GUIInput[GUI.resources.inputs()]; -		for (int i = 0; i < guiInputs.length; i++) { -			guiInputs[i] = new GUIInput(chromosome.getInput(i)); -		} -		// add inputs to content pane -		content.getChildren().addAll(guiInputs); - -		/* -		 * nodes -		 */ -		guiNodes = new GUINode[rows][columns]; -		for (int c = 0; c < columns; c++) { -			for (int r = 0; r < rows; r++) { -				// make the connection lines -				Line lines[] = new Line[GUI.resources.arity()]; -				for (int l = 0; l < lines.length; l++) { -					lines[l] = new Line(); -					lines[l].setMouseTransparent(true); -					lines[l].setVisible(false); -					connectionLines.add(lines[l]); -				} -				// make the GUI element -				guiNodes[r][c] = new GUINode(chromosome.getNode(r, c), lines); -				// add node to content pane -				content.getChildren().add(guiNodes[r][c]); -			} -		} - -		/*  -		 * outputs -		 */ -		guiOutputs = new GUIOutput[GUI.resources.outputs()]; -		for (int i = 0; i < guiOutputs.length; i++) { -			// make the connection line -			Line line = new Line(); -			line.setVisible(false); -			line.setMouseTransparent(true); -			connectionLines.add(line); -			// make the GUI element -			guiOutputs[i] = new GUIOutput(chromosome.getOutput(i), line); -		} -		// add outputs to content pane -		content.getChildren().addAll(guiOutputs); - -		// add lines to the pane on top of genes -		content.getChildren().addAll(connectionLines); - -		setPrefWidth(620); -		setContent(content); -	} - -	protected boolean isTarget() { -		return target; -	} - -	protected void setTarget(boolean newValue) { -		target = newValue; -	} - -	public void updateGenes(Chromosome chr) { -		for (int r = 0; r < GUI.resources.rows(); r++) { -			for (int c = 0; c < GUI.resources.columns(); c++) { -				guiNodes[r][c].setNode(chr.getNode(r, c)); -			} -		} -		for (int i = 0; i < guiOutputs.length; i++) { -			guiOutputs[i].setOutput(chr.getOutput(i)); -		} -	} - -	public static boolean isAllowed(GUIMutable source, GUIConnection target) { -		if (source instanceof GUINode) { -			// if the source is a node, all inputs and some nodes are valid -			if (target instanceof GUIInput) { -				return true; -			} else if (target instanceof GUINode) { -				// target and source are nodes, let's look at levels back -				Node t = ((GUINode) target).getNode(), s = ((GUINode) source).getNode(); -				if (s.getColumn() - t.getColumn() > 0 && s.getColumn() - t.getColumn() <= GUI.resources.levelsBack()) { -					return true; -				} -			} -			return false; -		} else if (source instanceof GUIOutput) { -			// if the source is an output, any node or input is valid -			if (target instanceof GUINode || target instanceof GUIInput) { -				return true; -			} else { -				// this should never happen... -				return false; -			} -		} -		// if the source was neither node nor output, something bad is happening -		throw new ClassCastException("Source was neither GUINode nor GUIOutput."); -	} -} diff --git a/src/jcgp/gui/population/FunctionSelector.java b/src/jcgp/gui/population/FunctionSelector.java deleted file mode 100644 index 14614e5..0000000 --- a/src/jcgp/gui/population/FunctionSelector.java +++ /dev/null @@ -1,80 +0,0 @@ -package jcgp.gui.population; - -import javafx.event.EventHandler; -import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.VBox; -import jcgp.backend.function.FunctionSet; -import jcgp.gui.constants.Constants; - -/** - * A menu class, exposes all of the allowed functions - * when called by a node, so that the node function can be changed. - *  - *  - * @author Eduardo Pedroni - * - */ -public class FunctionSelector extends VBox { -	 -	private GUINode target; -		 -	public FunctionSelector(FunctionSet functionSet) { -		setFillWidth(true); -		setVisible(false); -		setStyle("-fx-border-color: #A0A0A0; -fx-border-width: 1 1 0 1"); -		 -		remakeFunctions(functionSet); -		 -		addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() { -			@Override -			public void handle(MouseEvent event) { -				dismiss(); -			} -		}); -	} -	 -	public void remakeFunctions(final FunctionSet fs) { -		getChildren().clear(); -		 -		for (int i = 0; i < fs.getAllowedFunctionCount(); i++) { -			final int index = i; -			Label l = new Label(fs.getAllowedFunction(i).toString()); -			l.setMaxWidth(Double.MAX_VALUE); -			l.setStyle("-fx-background-color: #FFFFFF; -fx-border-color: #A0A0A0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); -			 -			l.addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() { -				@Override -				public void handle(MouseEvent event) { -					((Label) event.getSource()).setStyle("-fx-background-color: " + Constants.SOFT_HIGHLIGHT_PAINT + "; -fx-border-color: #B0B0B0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); -				} -			}); -			l.addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() { -				@Override -				public void handle(MouseEvent event) { -					((Label) event.getSource()).setStyle("-fx-background-color: #FFFFFF; -fx-border-color: #A0A0A0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); -				} -			}); -			l.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { -				@Override -				public void handle(MouseEvent event) { -					//target.setFunction(fs.getAllowedFunction(index)); -					dismiss(); -				} -			}); -			 -			getChildren().add(l); -		} -	} -	 -	public void relocateAndShow(MouseEvent event, GUINode node) { -		relocate(event.getSceneX() - 5, event.getSceneY() - 5); -		target = node; -		setVisible(true); -	} -	 -	private void dismiss() { -		setVisible(false); -	} -	 -} diff --git a/src/jcgp/gui/population/GUIConnection.java b/src/jcgp/gui/population/GUIConnection.java deleted file mode 100644 index dc7fcc8..0000000 --- a/src/jcgp/gui/population/GUIConnection.java +++ /dev/null @@ -1,32 +0,0 @@ -package jcgp.gui.population; - -import jcgp.gui.population.GUIGene.GUIGeneState; - -/** - * A loose equivalent to {@link jcgp.backend.population.Connection}. - * <br> - * This defines behaviour that all GUI representations of connections - * should be capable of. - *  - * @author Eduardo Pedroni - * - */ -public interface GUIConnection { - -	/** -	 * Set the connection's state, but also recursively propagate that state -	 * all the way back to the inputs. -	 *  -	 * @param state the state to set. -	 */ -	public void setStateRecursively(GUIGeneState state); -	 -	/** -	 * Add or remove a lock, but also recursively propagate that change -	 * all the way back to the inputs. -	 *  -	 * @param value true to lock, false to unlock. -	 */ -	public void setLockRecursively(boolean value); -	 -} diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java deleted file mode 100644 index 5e6107f..0000000 --- a/src/jcgp/gui/population/GUIGene.java +++ /dev/null @@ -1,187 +0,0 @@ -package jcgp.gui.population; - -import javafx.geometry.VPos; -import javafx.scene.Group; -import javafx.scene.paint.Paint; -import javafx.scene.shape.Circle; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.scene.text.TextAlignment; -import jcgp.gui.constants.Constants; - -/** - * Defines the general behaviour of the visual representation of each chromosome gene. - * <br><br> - * In practice, this is subclass of {@code javafx.scene.Group} containing a {@code Circle} - * object and a {@code Text} object. Subclasses may add further elements to the group, for - * instance to display connection input and output sockets. - * <br><br> - * Genes also contain a locked property. When locked, some gene states behave slightly - * differently. This is used so genes remain highlighted even in the neutral state. The - * gene lock is in fact recursive; a gene can be locked multiple times and only unlocking - * it as many times will actually revert it back to its unlocked state. This allows multiple - * pathways to lock the same gene independently without affecting each other; the gene remains - * locked until no pathways are locking it. - *  - * @author Eduardo Pedroni - * - */ -public abstract class GUIGene extends Group { - -	/** -	 * This {@code enum} type defines a finite list of all states -	 * a gene can take. Each state represents a particular steady -	 * situation, and has its own GUI appearance associated with it: -	 * a combination of connection line visibility, gene background colour -	 * and other visual characteristics. -	 *  -	 * @author Eduardo Pedroni -	 * -	 */ -	public enum GUIGeneState { -		/** -		 * No user interaction at all. -		 */ -		NEUTRAL, -		/** -		 * User is simply hovering over the node. -		 */ -		HOVER, -		/** -		 * User is hovering over a node connected to this one. -		 */ -		EXTENDED_HOVER, -		/** -		 * User is hovering over an output connected to this gene. -		 */ -		ACTIVE_HOVER, -		 -		GOOD_TARGET, -		 -		NEUTRAL_TARGET, -		 -		BAD_TARGET -	} - -	private GUIGeneState currentState = GUIGeneState.NEUTRAL; - -	private Text text; -	private Circle mainCircle; -	 -	/** -	 * Recursive lock; lock == 0 means unlocked, lock > 0 means locked. -	 * Accessing using {@code setLock(...)}. -	 */ -	private int lock = 0; - -	/** -	 * Initialises the {@code Text} and {@code Circle} objects so that all genes are standardised. -	 */ -	protected GUIGene() { -		text = new Text(); -		text.setFont(Font.font("Arial", 12)); -		text.setTextOrigin(VPos.CENTER); -		text.setTextAlignment(TextAlignment.CENTER); -		text.setWrappingWidth(Constants.NODE_RADIUS * 2); -		text.setX(-Constants.NODE_RADIUS); - -		mainCircle = new Circle(Constants.NODE_RADIUS, Constants.NEUTRAL_PAINT); -		mainCircle.setStroke(Paint.valueOf("black")); -		 -		getChildren().addAll(mainCircle, text); -	} - -	/** -	 * Sets the gene's text field. -	 *  -	 * @param newText the text string to be displayed. -	 */ -	public void setText(String newText) { -		text.setText(newText); -	} - -	/** -	 * @return the gene's current state. -	 */ -	public GUIGeneState getState() { -		return currentState; -	} - -	/** -	 * Gene states are standardised: all gene subclasses behave the same way in each state. -	 * <br> -	 * This design choice was made for the sake of consistency. Rather than controlling the  -	 * appearance of the genes with logic in the state transition method AND the mouse handlers,  -	 * the states are now consistent across all types of gene. The mouse handlers implement -	 * whatever logic is necessary to determine the gene's new state given a certain user input, -	 * but the states themselves are the same for all genes. -	 * <br> -	 * The transition logic for each type of gene is defined in its respective handler class: -	 * {@code InputHandlers}, {@code NodeHandlers} and {@code OutputHandlers}.    -	 *  -	 * @param newState the gene's new state. -	 */ -	public final void setState(GUIGeneState newState) { -		switch (newState) { -		case NEUTRAL: -			mainCircle.setFill(isLocked() ? Constants.HARD_HIGHLIGHT_PAINT : Constants.NEUTRAL_PAINT); -			setLinesVisible(isLocked()); -			break; -		case HOVER: -			mainCircle.setFill(Constants.MEDIUM_HIGHLIGHT_PAINT); -			setLinesVisible(true); -			break; -		case EXTENDED_HOVER: -			mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT); -			setLinesVisible(isLocked()); -			break; -		case ACTIVE_HOVER: -			mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT); -			setLinesVisible(true); -			break; -		case GOOD_TARGET: -			mainCircle.setFill(Constants.GOOD_SELECTION_PAINT); -			break; -		case NEUTRAL_TARGET: -			mainCircle.setFill(Constants.NEUTRAL_SELECTION_PAINT); -			break; -		case BAD_TARGET: -			mainCircle.setFill(Constants.BAD_SELECTION_PAINT); -			break; -		} -		currentState = newState; -	} -	 -	/** -	 * For the sake of practicality, all {@code GUIGene} instances must implement this -	 * method. It sets the visibility of all of the gene's lines, if it has any. -	 *  -	 * @param value the visibility value. -	 */ -	protected abstract void setLinesVisible(boolean value); -	 -	/** -	 * @return true if the gene is locked, false otherwise. -	 */ -	public boolean isLocked() { -		return lock > 0; -	} -	 -	/** -	 * Locks or unlocks the gene once. Locked genes -	 * behave slightly differently in some states.  -	 * <br> -	 * Unlocking an already unlocked gene does nothing. -	 *  -	 * @param value true to lock, false to unlock; -	 */ -	public void setLock(boolean value) { -		if (value) { -			lock++; -		} else if (lock > 0) { -			lock--; -		} else { -			lock = 0; -		} -	} -} diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java deleted file mode 100644 index 3db7416..0000000 --- a/src/jcgp/gui/population/GUIInput.java +++ /dev/null @@ -1,70 +0,0 @@ -package jcgp.gui.population; - -import javafx.scene.paint.Paint; -import javafx.scene.shape.Circle; -import jcgp.backend.population.Input; -import jcgp.gui.constants.Constants; -import jcgp.gui.constants.Position; -import jcgp.gui.handlers.InputHandlers; - -/** - * The GUI counterpart of {@link jcgp.backend.population.Input}. This is a  - * subclass of {@code GUIGene} which represents a chromosome input. - *  - * @author Eduardo Pedroni - */ -public class GUIInput extends GUIGene implements GUIConnection { - -	private Input input; -	 -	/** -	 * Instantiate {@code GUIInput} given an {@code Input}. -	 *  -	 * @param input the associated backend input. -	 */ -	public GUIInput(final Input input) { -		super(); -		// store the input, associate itself with it -		this.input = input; -		input.setGUIObject(this); -		 -		// inputs only have a single output socket -		Circle outputSocket = new Circle(Constants.NODE_RADIUS, 0, Constants.SOCKET_RADIUS, Paint.valueOf("white")); -		outputSocket.setStroke(Paint.valueOf("black")); -		outputSocket.setId(String.valueOf(0)); -		getChildren().add(outputSocket); -		 -		// relocate to the right position, add mouse handlers -		Position.place(this); -		InputHandlers.addHandlers(this); -	} - -	/** -	 * @return the {@code Input} instance associated with this object. -	 */ -	public Input getInput() { -		return input; -	} -	 -	/** -	 * Associates this instance with a new input. -	 *  -	 * @param input the new input. -	 */ -	void setInput(Input input) { -		this.input = input; -	} - -	@Override -	public void setStateRecursively(GUIGeneState state) { -		setState(state); -	} - -	@Override -	protected void setLinesVisible(boolean value) {} - -	@Override -	public void setLockRecursively(boolean value) { -		setLock(value); -	} -} diff --git a/src/jcgp/gui/population/GUIMutable.java b/src/jcgp/gui/population/GUIMutable.java deleted file mode 100644 index fa996e2..0000000 --- a/src/jcgp/gui/population/GUIMutable.java +++ /dev/null @@ -1,20 +0,0 @@ -package jcgp.gui.population; - -import javafx.scene.shape.Line; - -/** - * A loose equivalent to {@link jcgp.backend.population.Mutable}. - * <br> - * This defines behaviour that all GUI representations of mutables - * should be capable of. - *  - * @author Eduardo Pedroni - * - */ -public interface GUIMutable { -	 -	public Line[] getLines(); -	 -	public GUIConnection[] getConnections(); -	 -} diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java deleted file mode 100644 index 1a32426..0000000 --- a/src/jcgp/gui/population/GUINode.java +++ /dev/null @@ -1,134 +0,0 @@ -package jcgp.gui.population; - -import javafx.scene.paint.Paint; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import jcgp.backend.population.Gene; -import jcgp.backend.population.Node; -import jcgp.gui.GUI; -import jcgp.gui.constants.Constants; -import jcgp.gui.constants.Position; -import jcgp.gui.handlers.NodeHandlers; - -/** - * The GUI counterpart of {@link jcgp.backend.population.Node}. This is a  - * subclass of {@code GUIGene} which represents a chromosome node. - *  - * @author Eduardo Pedroni - */ -public class GUINode extends GUIGene implements GUIMutable, GUIConnection { - -	private Node node; -	private Line[] lines; -	private Circle[] sockets; -	 -	/** -	 * Instantiate {@code GUINode} given a {@code Node} and the lines needed -	 * to show its connections. -	 *  -	 * @param node the associated backend node. -	 * @param lines the lines used to display connections. -	 */ -	public GUINode(Node node, Line[] lines) { -		super(); -		// store references, associate with node -		this.node = node; -		this.lines = lines; -		node.setGUIObject(this); - -		// create the output socket -		Circle output = new Circle(Constants.NODE_RADIUS, 0, Constants.SOCKET_RADIUS, Constants.SOCKET_PAINT); -		output.setStroke(Paint.valueOf("black")); -		 -		// create input sockets -		sockets = new Circle[GUI.resources.arity()]; -		for (int l = 0; l < sockets.length; l++) { -			sockets[l] = new Circle(Constants.SOCKET_RADIUS, Constants.SOCKET_PAINT); -			sockets[l].setStroke(Paint.valueOf("black")); -			sockets[l].setId(String.valueOf(l)); -			// relocate them -			Position.placeSocket(l, sockets[l]); -			Position.connect(lines[l], (GUIGene) ((Gene) node.getConnection(l)).getGUIObject()); -		} -		 -		// add elements -		getChildren().addAll(sockets); -		getChildren().add(output); -		 -		// relocate node, add handlers -		Position.place(this); -		NodeHandlers.addHandlers(this); -	} -	 -	/** -	 * @return the {@code Node} instance associated with this object. -	 */ -	public Node getNode() { -		return node; -	} - -	/** -	 * Associates this instance with a new node. -	 *  -	 * @param node the new node. -	 */ -	void setNode(Node node) { -		this.node = node; -	} -	 -	@Override -	public Line[] getLines() { -		return lines; -	} -	 -	/** -	 * Returns one of this object's connection sockets. They are  -	 * indexed in the same order as lines and the connections -	 * they represent. -	 *  -	 * @param index the socket to return. -	 * @return the indexed socket object. -	 */ -	public Circle getSocket(int index) { -		return sockets[index]; -	} -	 -	/** -	 * @return the entire {@code Socket} array. -	 */ -	public Circle[] getSockets() { -		return sockets; -	} - -	@Override -	public void setStateRecursively(GUIGeneState state) { -		setState(state); -		for (int i = 0; i < GUI.resources.arity(); i++) { -			((GUIConnection) ((Gene) node.getConnection(i)).getGUIObject()).setStateRecursively(state); -		} -	} - -	@Override -	protected void setLinesVisible(boolean value) { -		for (int i = 0; i < lines.length; i++) { -			lines[i].setVisible(value); -		} -	} - -	@Override -	public void setLockRecursively(boolean value) { -		setLock(value); -		for (int i = 0; i < GUI.resources.arity(); i++) { -			((GUIConnection) ((Gene) node.getConnection(i)).getGUIObject()).setLockRecursively(value); -		} -	} - -	@Override -	public GUIConnection[] getConnections() { -		GUIConnection[] connections = new GUIConnection[GUI.resources.arity()]; -		for (int c = 0; c < connections.length; c++) { -			connections[c] = (GUIConnection) ((Gene) node.getConnection(c)).getGUIObject(); -		} -		return connections; -	} -} diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java deleted file mode 100644 index f023d00..0000000 --- a/src/jcgp/gui/population/GUIOutput.java +++ /dev/null @@ -1,79 +0,0 @@ -package jcgp.gui.population; - -import javafx.scene.paint.Paint; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import jcgp.backend.population.Gene; -import jcgp.backend.population.Output; -import jcgp.gui.constants.Constants; -import jcgp.gui.constants.Position; -import jcgp.gui.handlers.OutputHandlers; - -/** - * The GUI counterpart of {@link jcgp.backend.population.Output}. This is a  - * subclass of {@code GUIGene} which represents a chromosome output. - *  - * @author Eduardo Pedroni - */ -public class GUIOutput extends GUIGene implements GUIMutable { - -	private Output output; -	private Line line; - -	/** -	 * Instantiate {@code GUIOutput} given an {@code Output} and the line needed -	 * to show its connection. -	 *  -	 * @param output the associated backend output. -	 * @param line the line used to display connection. -	 */ -	public GUIOutput(final Output output, Line line) { -		super(); -		// store references, associate with backend object -		this.output = output; -		this.line = line; -		output.setGUIObject(this); - -		// create input socket -		Circle socket = new Circle(-Constants.NODE_RADIUS, 0, Constants.SOCKET_RADIUS, Constants.SOCKET_PAINT); -		socket.setStroke(Paint.valueOf("black")); -		socket.setId(String.valueOf(0)); -		Position.connect(line, (GUIGene) ((Gene) output.getSource()).getGUIObject()); -		getChildren().add(socket); - -		// relocate output, add handlers -		Position.place(this); -		OutputHandlers.addHandlers(this); -	} - -	/** -	 * @return the {@code Output} instance associated with this object. -	 */ -	public Output getOutput() { -		return output; -	} -	 -	/** -	 * Associates this instance with a new output. -	 *  -	 * @param output the new output. -	 */ -	void setOutput(Output output) { -		this.output = output; -	} - -	@Override -	public Line[] getLines() { -		return new Line[] {line}; -	} - -	@Override -	protected void setLinesVisible(boolean value) { -		line.setVisible(value); -	} - -	@Override -	public GUIConnection[] getConnections() { -		return new GUIConnection[] {(GUIConnection) output.getGUIObject()}; -	} -} diff --git a/src/jcgp/gui/population/PopulationPane.java b/src/jcgp/gui/population/PopulationPane.java deleted file mode 100644 index 51b5ba4..0000000 --- a/src/jcgp/gui/population/PopulationPane.java +++ /dev/null @@ -1,75 +0,0 @@ -package jcgp.gui.population; - -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import jcgp.JCGP; -import jcgp.backend.modules.problem.TestCaseProblem; -import jcgp.backend.modules.problem.TestCaseProblem.TestCase; -import jcgp.gui.GUI; - -public class PopulationPane extends TabPane { -	 -	private GUI gui; -	private TestCase<Object> currentTestCase; -	private boolean evaluating = false; -	 -	public PopulationPane(GUI gui) { -		super(); -		this.gui = gui; -		setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); -		remakeTabs(); -	} -	 -	public void remakeTabs() { -		getTabs().clear(); -		JCGP jcgp = gui.getExperiment(); -		 -		Tab tab; -		ChromosomePane cp; -		for (int i = 0; i < jcgp.getResources().populationSize(); i++) { -			cp = new ChromosomePane(jcgp.getPopulation().get(i)); -			tab = new Tab("Chr " + i); -			tab.setContent(cp); -			getTabs().add(tab); -		} -	} -		 -	public void updateGenes() { -		if (evaluating) { -			evaluateTestCase(currentTestCase); -		} -		for (int i = 0; i < getTabs().size(); i++) { -			((ChromosomePane) getTabs().get(i).getContent()).updateGenes(gui.getExperiment().getPopulation().get(i)); -		} -	} -	 -	public void evaluateTestCase(TestCase<Object> testCase) { -		if (gui.getExperiment().getProblem() instanceof TestCaseProblem && testCase != null) { -			currentTestCase = testCase; -			if (testCase.getInputs().length == gui.getExperiment().getResources().inputs()) { -				evaluating = true; -				for (int i = 0; i < getTabs().size(); i++) { -					//((ChromosomePane) getTabs().get(i).getContent()).setInputs(testCase.getInputs()); -				} -			} else { -				throw new IllegalArgumentException("Test case has " + testCase.getInputs().length -						+ " inputs and chromosome has " + gui.getExperiment().getResources().inputs()); -			} -		} -	} -	 -	public void hideValues() { -		evaluating = false; -		for (int i = 0; i < getTabs().size(); i++) { -			//((ChromosomePane) getTabs().get(i).getContent()).updateValues(); -		} -	} - -	public boolean isEvaluating() { -		return evaluating; -	} - -	public void setEvaluating(boolean value) { -		evaluating = value; -	} -} diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java deleted file mode 100644 index bad42cd..0000000 --- a/src/jcgp/gui/settings/SettingsPane.java +++ /dev/null @@ -1,595 +0,0 @@ -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(); -	} -} diff --git a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java deleted file mode 100644 index a1f03fe..0000000 --- a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java +++ /dev/null @@ -1,82 +0,0 @@ -package jcgp.gui.settings.parameters; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Control; -import jcgp.backend.parameters.BooleanParameter; -import jcgp.backend.parameters.ParameterStatus; -import jcgp.gui.constants.Constants; -import jcgp.gui.settings.SettingsPane; - -/** - * This extension of @code{GUIParameter} uses a @code{CheckBox} to display - * the value of a @code{BooleanParameter}. It cannot be constructed - * directly - instead, use @code{GUIParameter.create()}. - * <br><br> - * See {@link GUIParameter} for more information. - *  - * @author Eduardo Pedroni - */ -public class GUIBooleanParameter extends GUIParameter<Boolean> { - -	private CheckBox checkBox; -	 -	/** -	 * This protected constructor is intended for use -	 * by the factory method only. -	 *  -	 */ -	protected GUIBooleanParameter(BooleanParameter parameter, SettingsPane sp) { -		super(parameter, sp); -	} -	 -	@Override -	protected Control makeControl() { -		checkBox = new CheckBox(); -		checkBox.setSelected(parameter.get()); -		 -		return checkBox; -	} -	 -	@Override -	protected void setControlListeners() { -		/* pass the CheckBox value back to the parameter whenever it gets -		 * modified, provided the experiment isn't running */ -		checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() { -			@Override -			public void changed( -					ObservableValue<? extends Boolean> observable, -					Boolean oldValue, Boolean newValue) { -				if (!settingsPane.isExperimentRunning()) { -					parameter.set(newValue); -					settingsPane.revalidateParameters(); -				} -			} -		}); -	} -	 -	@Override -	protected void setValidityStyle() { -		// update the Control's style and tooltip based on the status of the parameter -		if (parameter.getStatus() == ParameterStatus.INVALID) { -			checkBox.setStyle(Constants.BASE_CHECKBOX_STYLE + Constants.INVALID_PARAMETER_STYLE); -			checkBox.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else if (parameter.getStatus() == ParameterStatus.WARNING  -				|| parameter.getStatus() == ParameterStatus.WARNING_RESET) { -			checkBox.setStyle(Constants.BASE_CHECKBOX_STYLE + Constants.WARNING_PARAMETER_STYLE); -			checkBox.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else { -			checkBox.setStyle(Constants.BASE_CHECKBOX_STYLE + Constants.VALID_PARAMETER_STYLE); -			checkBox.setTooltip(null); -		} -	} - -	@Override -	public void refreshValue() { -		checkBox.setSelected(parameter.get()); -	} -	 -} diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java deleted file mode 100644 index feee34c..0000000 --- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java +++ /dev/null @@ -1,110 +0,0 @@ -package jcgp.gui.settings.parameters; - -import java.text.DecimalFormat; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Pos; -import javafx.scene.control.Control; -import javafx.scene.control.TextField; -import jcgp.backend.parameters.DoubleParameter; -import jcgp.backend.parameters.ParameterStatus; -import jcgp.gui.constants.Constants; -import jcgp.gui.settings.SettingsPane; - -/** - * This extension of @code{GUIParameter} uses a @code{TextField} to display - * the value of a @code{DoubleParameter}. It cannot be constructed - * directly - instead, use @code{GUIParameter.create()}. - * <br><br> - * See {@link GUIParameter} for more information. - *  - * @author Eduardo Pedroni - */ -public class GUIDoubleParameter extends GUIParameter<Number> { - -	private TextField textField; -	private DecimalFormat decimalFormat; -	 -	/** -	 * This protected constructor is intended for use -	 * by the factory method only. -	 *  -	 */ -	protected GUIDoubleParameter(DoubleParameter parameter, SettingsPane sp) { -		super(parameter, sp); -	} -	 -	@Override -	protected Control makeControl() { -		// we use a text field, and a formatting class to enforce decimals -		decimalFormat = new DecimalFormat(); -		decimalFormat.setMaximumFractionDigits(10); -		textField = new TextField(decimalFormat.format(parameter.get().doubleValue())); -		textField.setStyle(Constants.VALID_PARAMETER_STYLE); -		textField.setAlignment(Pos.CENTER_RIGHT); -		textField.prefWidthProperty().bind(widthProperty().divide(2)); -		return textField; -	} - -	@Override -	protected void setControlListeners() { -		/* pass the TextField value back to the parameter whenever it gets -		 * modified, provided it is not empty, the experiment isn't running -		 * and it matches the double-precision regex filter */ -		textField.textProperty().addListener(new ChangeListener<String>() { -			@Override -			public void changed( -					ObservableValue<? extends String> observable, -					String oldValue, String newValue) { -				if (!settingsPane.isExperimentRunning()) { -					if (newValue.matches("^[-+]?[0-9]*\\.?[0-9]+$")) { -						if (!newValue.isEmpty()) { -							double value = Double.parseDouble(newValue); -							parameter.set(value); -							settingsPane.revalidateParameters(); -						} -					} else { -						refreshValue(); -					} -				} -			} -		}); -		/* if the TextField loses focus and is empty, set it to the current -		 * value of the parameter */ -		textField.focusedProperty().addListener(new ChangeListener<Boolean>() { -			@Override -			public void changed( -					ObservableValue<? extends Boolean> observable, -					Boolean oldValue, Boolean newValue) { -				if (!newValue) { -					refreshValue(); -				} -			} -		}); -	} - -	@Override -	protected void setValidityStyle() { -		// update the Control's style and tooltip based on the status of the parameter -		if (parameter.getStatus() == ParameterStatus.INVALID) { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.INVALID_PARAMETER_STYLE); -			textField.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else if (parameter.getStatus() == ParameterStatus.WARNING || parameter.getStatus() ==  ParameterStatus.WARNING_RESET) { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.WARNING_PARAMETER_STYLE); -			textField.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.VALID_PARAMETER_STYLE); -			textField.setTooltip(null); -		} -	} -	 -	@Override -	public void refreshValue() { -		if (!textField.isFocused()) { -			textField.setText(decimalFormat.format(parameter.get().doubleValue())); -		} -	} -} diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java deleted file mode 100644 index bcfbe50..0000000 --- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java +++ /dev/null @@ -1,107 +0,0 @@ -package jcgp.gui.settings.parameters; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Pos; -import javafx.scene.control.Control; -import javafx.scene.control.TextField; -import jcgp.backend.parameters.IntegerParameter; -import jcgp.backend.parameters.ParameterStatus; -import jcgp.gui.constants.Constants; -import jcgp.gui.settings.SettingsPane; - -/** - * This extension of @code{GUIParameter} uses a @code{TextField} to display - * the value of a @code{IntegerParameter}. It cannot be constructed - * directly - instead, use @code{GUIParameter.create()}. - * <br><br> - * See {@link GUIParameter} for more information. - *  - * @author Eduardo Pedroni - */ -public class GUIIntegerParameter extends GUIParameter<Number> { -	 -	private TextField textField; -	 -	/** -	 * This protected constructor is intended for use -	 * by the factory method only. -	 *  -	 */ -	protected GUIIntegerParameter(IntegerParameter parameter, SettingsPane sp) { -		super(parameter, sp); -	} - -	@Override -	protected Control makeControl() { -		// this uses a text field -		textField = new TextField(String.valueOf(parameter.get())); -		textField.setStyle(Constants.VALID_PARAMETER_STYLE); -		textField.setAlignment(Pos.CENTER_RIGHT); -		textField.prefWidthProperty().bind(widthProperty().divide(2)); -		 -		return textField; -	} - -	@Override -	protected void setControlListeners() { -		/* pass the TextField value back to the parameter whenever it gets -		 * modified, provided it is not empty, the experiment isn't running -		 * and it matches the integer regex pattern */ -		textField.textProperty().addListener(new ChangeListener<String>() { -			@Override -			public void changed( -					ObservableValue<? extends String> observable, -					String oldValue, String newValue) { -				if (!settingsPane.isExperimentRunning()) { -					if (newValue.matches("[0-9]*")) { -						if (!newValue.isEmpty()) { -							int value = Integer.parseInt(newValue); -							parameter.set(value); -							settingsPane.revalidateParameters(); -						} -					} else { -						refreshValue(); -					} -				} -			} -		}); -		/* if the TextField loses focus and is empty, set it to the current -		 * value of the parameter */ -		textField.focusedProperty().addListener(new ChangeListener<Boolean>() { -			@Override -			public void changed( -					ObservableValue<? extends Boolean> observable, -					Boolean oldValue, Boolean newValue) { -				if (!newValue) { -					refreshValue(); -				} -			} -		}); -	} -	 -	@Override -	protected void setValidityStyle() { -		// update the Control's style and tooltip based on the status of the parameter -		if (parameter.getStatus() == ParameterStatus.INVALID) { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.INVALID_PARAMETER_STYLE); -			textField.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else if (parameter.getStatus() == ParameterStatus.WARNING  -				|| parameter.getStatus() ==  ParameterStatus.WARNING_RESET) { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.WARNING_PARAMETER_STYLE); -			textField.setTooltip(tooltip); -			tooltip.setText(parameter.getStatus().getDetails()); -		} else { -			textField.setStyle(Constants.BASE_TEXT_STYLE + Constants.VALID_PARAMETER_STYLE); -			textField.setTooltip(null); -		} -	} - -	@Override -	public void refreshValue() { -		if (!textField.isFocused()) { -			textField.setText(parameter.get().toString()); -		} -	} -} diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java deleted file mode 100644 index 59aecf6..0000000 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ /dev/null @@ -1,235 +0,0 @@ -package jcgp.gui.settings.parameters; - -import java.util.concurrent.atomic.AtomicBoolean; - -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Pos; -import javafx.scene.control.Control; -import javafx.scene.control.Label; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.HBox; -import jcgp.backend.parameters.BooleanParameter; -import jcgp.backend.parameters.DoubleParameter; -import jcgp.backend.parameters.IntegerParameter; -import jcgp.backend.parameters.Parameter; -import jcgp.backend.parameters.ParameterStatus; -import jcgp.gui.settings.SettingsPane; - -/** - *  - * This is the base class for all @code{GUIParameter}s. Using the factory method @code{GUIParameter.create()} - * generates an appropriate instance of this class for the specified parameter. - * <br><br> - * A @code{GUIParameter} is an @code{HBox} containing a @code{Text} for the parameter name  - * and a @code{Control} for interaction. - * It stores an instance of its associated @code{Parameter} object and also contains a @code{Tooltip} for  - * displaying status information. - * <br><br> - * Monitor parameters are updated automatically and have their @code{Control} disabled so - * that no changes can be made via the GUI. - * Non-monitor parameters are updated automatically as well, but may be changed by the user - * if the program is not evolving. - *  - * @see Parameter - * @author Eduardo Pedroni - * @param <T> the parameter data type - */ -public abstract class GUIParameter<T> extends HBox { -	 -	private Label name; -	private Control valueControl; -	 -	protected SettingsPane settingsPane; -	protected Tooltip tooltip; -	protected Parameter<T> parameter; -	 -	/** This is the lock used to prevent more than one update task to be scheduled -	 *  at the same time on the same GUIParameter. */ -	private AtomicBoolean updateLock = new AtomicBoolean(false); -	 -	/** -	 * This value is used to assert whether the control has changed values since  -	 * the program last ran. Therefore, it is updated whenever a generation occurs -	 * or the experiment is reset. -	 */ -	private T referenceValue; -	 -	/** -	 * This protected template constructor contains the common elements to all -	 * @code{GUIParameter}s and should be invoked by any subclasses using @code{super()}. It -	 * defers the creation of the parameter {@code Control} object to the subclass -	 * currently being built (which in turn is defined by the factory method). -	 *  -	 * @param parameter a @code{Parameter} for which to generate a @code{GUIParameter}. -	 * @param sp a reference to the @code{SettingsPane}. -	 */ -	protected GUIParameter(Parameter<T> parameter, final SettingsPane settingsPane) { -		this.parameter = parameter; -		this.referenceValue = parameter.get(); -		 -		this.settingsPane = settingsPane; -		 -		setAlignment(Pos.CENTER_LEFT); -		setSpacing(5); -		 -		name = new Label(parameter.toString()); -		// set text width to half of the total width of the GUIParameter -		name.prefWidthProperty().bind(widthProperty().divide(2)); -		 -		// the tooltip is the hover-over label containing status information, when appropriate -		tooltip = new Tooltip(); -		tooltip.setSkin(null); -		 -		valueControl = makeControl(); -		 -		// if the parameter is a monitor, it should be permanently disabled -		valueControl.setDisable(parameter.isMonitor()); -		 -		// bind to parameter value property in a thread-safe way -		makeThreadSafeBinding(); -		 -		// if parameter is not a monitor, make sure the control is constrained appropriately -		if (!parameter.isMonitor()) { -			setControlListeners(); -		} -		 -		getChildren().addAll(name, valueControl); -	} -	 -	/** -	 * Factory method to create @code{GUIParameter}s from @code{Parameter}s.  -	 * Use this to create an appropriate @code{GUIParameter} from any instance of @code{Parameter}, -	 * rather than manually downcasting the @code{Parameter} object every time. -	 *  -	 * @param parameter a parameter for which to generate a @code{GUIParameter}. -	 * @param sp a reference to the @code{SettingsPane}. -	 * @return an appropriate instance of @code{GUIParameter}. -	 */ -	public static GUIParameter<?> create(Parameter<?> parameter, SettingsPane sp) { -		if (parameter instanceof IntegerParameter) { -			return new GUIIntegerParameter((IntegerParameter) parameter, sp); -		} else if (parameter instanceof DoubleParameter) { -			return new GUIDoubleParameter((DoubleParameter) parameter, sp); -		} else if (parameter instanceof BooleanParameter) { -			return new GUIBooleanParameter((BooleanParameter) parameter, sp); -		} else { -			throw new ClassCastException("No GUIParameter subclass exists for argument of type " + parameter.getClass()); -		} -	} - -	/** -	 * Parameters are intended to communicate information from the experiment -	 * to the GUI. Since the experiment runs on a separate threads and it is illegal -	 * to modify JavaFX objects from outside the JavaFX Application thread, this -	 * special ChangeListener updates the GUIParameter in a safe way. -	 * <br><br> -	 * Note that this is applied to all parameters regardless of whether they are  -	 * monitors or not; the only difference between monitor and non-monitor parameters -	 * is that monitor parameters cannot be modified from the GUI. -	 */ -	private void makeThreadSafeBinding() { -		parameter.valueProperty().addListener(new ChangeListener<Object>() { -			@Override -			public void changed( -					ObservableValue<? extends Object> observable, -					Object oldValue, Object newValue) { -				// only do this if the experiment is running -				if (settingsPane.isExperimentRunning() || !isFocused()) { -					/* here's the catch - atomically get the lock state and set it to true -					 * the lock will only be false again when the runnable is finished executing,  -					 * preventing multiple runnables to concurrently update the same GUIParameter -					 */ -					if (!updateLock.getAndSet(true)) { -						Platform.runLater(new Runnable() { -							@Override -							public void run() { -								refreshValue(); -								updateLock.set(false); -							} -						}); -					} -				} -			} -		}); -	} -	 -	/** -	 * @return true if the current value of the parameter does not prevent the  -	 * experiment from running. -	 */ -	public boolean isValid() { -		return parameter.getStatus() != ParameterStatus.INVALID; -	} -	 -	/** -	 * Force the parameter to validate its current value, and apply the associated -	 * style to the @code{GUIParameter}. -	 */ -	public void validate() { -		parameter.validate(parameter.get()); -		setValidityStyle(); -	} -	 -	/** -	 * Certain parameter changes might require the experiment to be reset, either -	 * because the parameter is critical or because its status requires a reset. -	 *  -	 * @return true if an experiment reset is required due to this parameter changing. -	 */ -	public boolean requiresReset() { -		return (parameter.isCritical() && !parameter.get().equals(referenceValue)) -				|| parameter.getStatus() == ParameterStatus.WARNING_RESET; -	} -	 -	/** -	 * Set the current parameter value as the reference value of the @code{GUIParameter}. -	 * The new reference value will be used to determine the validity of the parameter,  -	 * should its value change. -	 */ -	public void applyValue() { -		referenceValue = parameter.get(); -	} -	 -	/*  -	 * The following prototypes are instance-dependent and are called from -	 * GUIParameter() as necessary. -	 */ -	/** -	 * This method returns the @code{Control} object used to control the parameter. -	 * <br><br> -	 * Implementations of @code{GUIParameter} must override this method and return  -	 * a @code{Control} appropriate to the type of parameter. This will typically be -	 * done by referencing the protected field @code{GUIParameter.parameter}. -	 *  -	 * @return the Control object to be added to the GUIParameter. -	 */ -	protected abstract Control makeControl(); -	 -	/** -	 * Adds the necessary handlers to the @code{Control} object in order to modify -	 * the underlying parameter. This will typically consist of filtering key -	 * presses to ensure no invalid characters are inserted, applying the new  -	 * value to the underlying parameter and revalidating the parameters to -	 * reflect the changes made. -	 */ -	protected abstract void setControlListeners(); -	 -	/** -	 * This method is called to style the @code{GUIParameter} according to the status of -	 * the parameter, which can be obtained with @code{parameter.getStatus()}. While the -	 * subclass is free to style itself in any way, the CSS strings defined here  -	 * (INVALID_PARAMETER_STYLE, WARNING_PARAMETER_STYLE, VALID_PARAMETER_STYLE) -	 * provide a way to keep the GUI consistent. -	 *  -	 * @see ParameterStatus -	 */ -	protected abstract void setValidityStyle(); -	 -	/** -	 * Update the control so it shows the correct value of the parameter. This method -	 * is used exclusively by the thread-safe binding created if the module is a monitor. -	 */ -	protected abstract void refreshValue(); -} diff --git a/src/jcgp/gui/settings/testcase/TestCaseTable.java b/src/jcgp/gui/settings/testcase/TestCaseTable.java deleted file mode 100644 index 605b75e..0000000 --- a/src/jcgp/gui/settings/testcase/TestCaseTable.java +++ /dev/null @@ -1,124 +0,0 @@ -package jcgp.gui.settings.testcase; - -import java.util.ArrayList; - -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableColumn.CellDataFeatures; -import javafx.scene.control.TableView; -import javafx.stage.Stage; -import javafx.stage.WindowEvent; -import javafx.util.Callback; -import jcgp.backend.modules.problem.TestCaseProblem; -import jcgp.backend.modules.problem.TestCaseProblem.TestCase; -import jcgp.backend.resources.Resources; -import jcgp.gui.GUI; - -/** - * This is a test case table. For problems that have test cases,  - * this table shows the test case inputs and outputs. Clicking on  - * a test case (one is shown per row) applies the values to all  - * chromosome inputs shows the calculated values throughout the chromosome. - *  - * @author Eduardo Pedroni - * - */ -public class TestCaseTable extends Stage { - -	private TableView<TestCase<Object>> table; - -	/** -	 * Make a new instance of {@code TestCaseTable}. -	 *  -	 * @param testCaseProblem the {@code TestCaseProblem} whose data must be displayed. -	 * @param gui a reference to the GUI. -	 */ -	public TestCaseTable(final TestCaseProblem<Object> testCaseProblem, final GUI gui) { -		super(); -		 -		Resources resources = gui.getExperiment().getResources(); -		 -		// create the actual table view -		table = new TableView<TestCase<Object>>(); -		// get test cases from problem -		ObservableList<TestCase<Object>> testCaseList = testCaseProblem.getTestCases(); -		 -		// prepare input and output columns -		ArrayList<TableColumn<TestCase<Object>, String>> inputs = new ArrayList<TableColumn<TestCase<Object>, String>>(resources.inputs()); -		ArrayList<TableColumn<TestCase<Object>, String>> outputs = new ArrayList<TableColumn<TestCase<Object>, String>>(resources.outputs()); - -		// create input columns -		TableColumn<TestCase<Object>, String> tc; -		for (int i = 0; i < resources.inputs(); i++) { -			tc = new TableColumn<TestCase<Object>, String>("I: " + i); -			inputs.add(tc); -			final int index = i; -			tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TestCase<Object>,String>, ObservableValue<String>>() { -				@Override -				public ObservableValue<String> call(CellDataFeatures<TestCase<Object>, String> param) { -					// create a new string property and give it the test case value, no need for dynamic binding - this wont change often -					return new SimpleStringProperty(param.getValue().getInputs()[index].toString()); -				} -			}); -			tc.setSortable(false); -			// set column width so all columns are distributed across the width of the stage -			tc.prefWidthProperty().bind(table.widthProperty().divide(resources.inputs() + resources.outputs())); -		} -		 -		// create output columns -		for (int o = 0; o < resources.outputs(); o++) { -			tc = new TableColumn<TestCase<Object>, String>("O: " + o); -			outputs.add(tc); -			final int index = o; -			tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<TestCase<Object>,String>, ObservableValue<String>>() { -				@Override -				public ObservableValue<String> call(CellDataFeatures<TestCase<Object>, String> param) { -					// create a new string property and give it the test case value, no need for dynamic binding - this wont change often -					return new SimpleStringProperty(param.getValue().getOutputs()[index].toString()); -				} -			}); -			tc.setSortable(false); -			// set column width so all columns are distributed across the width of the stage -			tc.prefWidthProperty().bind(table.widthProperty().divide(resources.inputs() + resources.outputs())); -		} -		 -		// add created columns -		table.getColumns().addAll(inputs); -		table.getColumns().addAll(outputs); -		 -		// populate table with actual data -		table.setItems(testCaseList); -		 -		// apply test case values when a new test case is selected -		table.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TestCase<Object>>() { -			@Override -			public void changed(ObservableValue<? extends TestCase<Object>> observable,	TestCase<Object> oldValue, TestCase<Object> newValue) { -				gui.evaluateTestCase(newValue); -			} -		}); -		 -		// when the stage is closed, clear the selection -		// this doesn't work if the stage is closed by the program for some reason... -		setOnCloseRequest(new EventHandler<WindowEvent>() { -			@Override -			public void handle(WindowEvent event) { -				gui.hideGeneValues(); -				table.getSelectionModel().clearSelection(); -			} -		}); -		 -		setScene(new Scene(table)); -	} - -	/** -	 * @return a reference to the actual table of test cases. -	 */ -	public TableView<TestCase<Object>> getTable() { -		return table; -	} -} | 
