<commit_before>package ui.components;

import java.util.Optional;
import java.util.function.IntConsumer;

import javafx.scene.input.KeyCode;

/**
 * A very specialized ListView subclass that:
 * 
 * - can be navigated with the arrow keys and Enter
 * - supports an event for item selection
 * - provides methods for retaining selection after its contents are changed
 * 
 * It depends on the functionality of ScrollableListView to ensure that
 * navigation scrolls the list properly. The Up, Down, and Enter key events
 * should not be separately bound on it.
 * 
 * An item is considered selected when:
 * 
 * - it is highlighted with the arrow keys, but only when the Shift key is not down
 * - Enter is pressed when it is highlighted
 * - it is clicked
 */
public class NavigableListView<T> extends ScrollableListView<T> {

	// Tracks the index of the list which should be currently selected
	private Optional<Integer> selectedIndex = Optional.empty();
	
	// Used for saving and restoring selection
	private Optional<T> selectedItem = Optional.empty();
	
	// Indicates that saveSelection was called, in the event that saveSelection itself fails
	// (when nothing is selected, both should be no-ops)
	private boolean saveSelectionCalled = false;

	private IntConsumer onItemSelected = i -> {};
	
	public NavigableListView() {
		setupKeyEvents();
		setupMouseEvents();
	}
	
	/**
	 * Should be called before making changes to the item list of this list view if
	 * it's important that selection is retained after.
	 */
	public void saveSelection() {
		if (getSelectionModel().getSelectedItem() != null) {
			selectedItem = Optional.of(getSelectionModel().getSelectedItem());
		}
		saveSelectionCalled = true;
	}
	
	/**
	 * Should be called to restore selection after making changes to the item list
	 * of this list view. Must be called after saveSelection is.
	 * @throws IllegalStateException if called before saveSelection is
	 */
	public void restoreSelection() {
		if (!selectedItem.isPresent()) {
			if (!saveSelectionCalled) {
				throw new IllegalStateException("saveSelection must be called before restoreSelection");
			} else {
				saveSelectionCalled = false;
				return; // No-op
			}
		}
		saveSelectionCalled = false;
		
		// Find index of previously-selected item
		int index = -1;
		int i = 0;
		for (T item : getItems()) {
			if (item.equals(selectedItem)) {
				index = i;
				break;
			}
			i++;
		}
		
		if (index == -1) {
			// The item disappeared; do nothing, as selection will be resolved on its own
		} else {
			// Select that item
			getSelectionModel().clearAndSelect(index);
			selectedIndex = Optional.of(index);
			// Do not trigger event
		}
	}

	private void setupMouseEvents() {
		setOnMouseClicked(e -> {
			selectedIndex = Optional.of(getSelectionModel().getSelectedIndex());
			onItemSelected.accept(selectedIndex.get());
		});
	}

	private void setupKeyEvents() {
		setOnKeyPressed(e -> {
			switch (e.getCode()) {
			case UP:
			case DOWN:
				e.consume();
				handleUpDownKeys(e.getCode() == KeyCode.DOWN);
				assert selectedIndex.isPresent() : "handleUpDownKeys doesn't set selectedIndex!";
				if (!e.isShiftDown()) {
					onItemSelected.accept(selectedIndex.get());
				}
				break;
			case ENTER:
				e.consume();
				if (selectedIndex.isPresent()) {
					onItemSelected.accept(selectedIndex.get());	
				}
				break;
			default:<commit_msg>Added logging for different methods of issue selection<commit_after>package ui.components;

import java.util.Optional;
import java.util.function.IntConsumer;

import javafx.scene.input.KeyCode;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * A very specialized ListView subclass that:
 * 
 * - can be navigated with the arrow keys and Enter
 * - supports an event for item selection
 * - provides methods for retaining selection after its contents are changed
 * 
 * It depends on the functionality of ScrollableListView to ensure that
 * navigation scrolls the list properly. The Up, Down, and Enter key events
 * should not be separately bound on it.
 * 
 * An item is considered selected when:
 * 
 * - it is highlighted with the arrow keys, but only when the Shift key is not down
 * - Enter is pressed when it is highlighted
 * - it is clicked
 */
public class NavigableListView<T> extends ScrollableListView<T> {

	private static final Logger logger = LogManager.getLogger(NavigableListView.class.getName());

	// Tracks the index of the list which should be currently selected
	private Optional<Integer> selectedIndex = Optional.empty();
	
	// Used for saving and restoring selection
	private Optional<T> selectedItem = Optional.empty();
	
	// Indicates that saveSelection was called, in the event that saveSelection itself fails
	// (when nothing is selected, both should be no-ops)
	private boolean saveSelectionCalled = false;

	private IntConsumer onItemSelected = i -> {};
	
	public NavigableListView() {
		setupKeyEvents();
		setupMouseEvents();
	}
	
	/**
	 * Should be called before making changes to the item list of this list view if
	 * it's important that selection is retained after.
	 */
	public void saveSelection() {
		if (getSelectionModel().getSelectedItem() != null) {
			selectedItem = Optional.of(getSelectionModel().getSelectedItem());
		}
		saveSelectionCalled = true;
	}
	
	/**
	 * Should be called to restore selection after making changes to the item list
	 * of this list view. Must be called after saveSelection is.
	 * @throws IllegalStateException if called before saveSelection is
	 */
	public void restoreSelection() {
		if (!selectedItem.isPresent()) {
			if (!saveSelectionCalled) {
				throw new IllegalStateException("saveSelection must be called before restoreSelection");
			} else {
				saveSelectionCalled = false;
				return; // No-op
			}
		}
		saveSelectionCalled = false;
		
		// Find index of previously-selected item
		int index = -1;
		int i = 0;
		for (T item : getItems()) {
			if (item.equals(selectedItem)) {
				index = i;
				break;
			}
			i++;
		}
		
		if (index == -1) {
			// The item disappeared; do nothing, as selection will be resolved on its own
		} else {
			// Select that item
			getSelectionModel().clearAndSelect(index);
			selectedIndex = Optional.of(index);
			// Do not trigger event
		}
	}

	private void setupMouseEvents() {
		setOnMouseClicked(e -> {
			logger.info("Mouse click on issue " + selectedIndex.get());
			onItemSelected.accept(selectedIndex.get());
		});
	}

	private void setupKeyEvents() {
		setOnKeyPressed(e -> {
			switch (e.getCode()) {
			case UP:
			case DOWN:
				e.consume();
				handleUpDownKeys(e.getCode() == KeyCode.DOWN);
				assert selectedIndex.isPresent() : "handleUpDownKeys doesn't set selectedIndex!";
				if (!e.isShiftDown()) {
					logger.info("Arrow key navigation to issue " + selectedIndex.get());
					onItemSelected.accept(selectedIndex.get());
				}
				break;
			case ENTER:
				e.consume();
				if (selectedIndex.isPresent()) {
					logger.info("Enter key selection on issue " + selectedIndex.get());
					onItemSelected.accept(selectedIndex.get());	
				}
				break;
			default:
{'fraction_non_alphanumeric': 0.09966358284272497, 'fraction_numerical': 0.00112139052425007, 'mean_word_length': 3.570787956438181, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3507138', 'n_tokens_mistral': 2265, 'n_tokens_neox': 1955, 'n_words': 695}