<commit_before>package com.github.thbrown.actionrecorder;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.text.DefaultCaret;

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;

/**
 * This is the main class for the ActionRecorder application.
 * 
 * This applications records mouse and keyboard presses and mouse movement. The recordings can then be played back.
 * @author thbrown
 */
public class Main extends JFrame implements ActionListener, WindowListener {

	// UI objects
	private JPanel mainPanel;
	private JButton startRecording;
	private JButton stopRecording;
	private JButton replay;
	private StatusArea statusConsole;
	private JLabel mousePositionTextDataLabel;
	private JLabel mouseColorTextDataLabel;
	private JPanel mouseColorDataLabel;

	// JNativeHook library objects
	private GlobalKeyboardListener keyboardListener;
	private GlobalMouseListener mouseListener;
	private GlobalMouseWheelListener mouseWheelListener;
	
	// Storages object to store save recorded data
	private Storage dataHolder;
	private Storage dataGarbageCan;
	
	// A handle for the thread used to playback data
	private Playback playbackThread;
	
	// Layout parameters
	private static final int MOUSE_INFO_PANEL_HEIGHT = 25;
	private static final int MOUSE_INFO_PANEL_COLOR_WIDTH = 50;
	private static final int MOUSE_INFO_PANEL_COLOR_TEXT_WIDTH = 85;
	
	public static void main(String[] args) {
		Main m = new Main("ActionRecorder");
		m.setVisible(true);
	}

	public Main(String title) {
		setTitle(title);
		setPreferredSize(new Dimension(500,350));
		setMinimumSize(getPreferredSize());
		this.addWindowListener(this);

		mainPanel = new JPanel();
		this.addUIComponents(mainPanel);
		this.add(mainPanel, BorderLayout.CENTER);
		this.setFocusable(true);
		
		// Create the menu bar.
		JMenuBar menuBar = new JMenuBar();

		// Build the first menu.
		JMenu menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_A);
		menu.getAccessibleContext().setAccessibleDescription("The only menu in this program that has menu items");
		menuBar.add(menu);

		// A group of JMenuItems
		JMenuItem menuItem = new JMenuItem("Exit", KeyEvent.VK_T);
		menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
		menuItem.getAccessibleContext().setAccessibleDescription("This doesn't really do anything");
		menuItem.addActionListener(this);
		menu.add(menuItem);
		
		// Attach the menu to the JFrame
		this.setJMenuBar(menuBar);
		
		// Initialize storage objects, one that saves command data and one that discards it
		dataHolder = new ListStorage(statusConsole);
		dataGarbageCan = new BlackholeStorage();
		
		// Initialize the jnativehook Library
		try {
			GlobalScreen.registerNativeHook();
		} catch (NativeHookException ex) {
			String errorMessage = "Error: There was a problem registering the native hook.";
			statusConsole.append(errorMessage);
			statusConsole.append(ex.getMessage());
			startRecording.setEnabled(true);
			return;
		}

		// Initialize the jnativehook Keyboard Listener
		keyboardListener = new GlobalKeyboardListener(dataGarbageCan, statusConsole);
		GlobalScreen.getInstance().addNativeKeyListener(keyboardListener);

		// Initialize the jnativehook Mouse Click/Movement Listener
		mouseListener = new GlobalMouseListener(dataGarbageCan, statusConsole, this);
		GlobalScreen.getInstance().addNativeMouseListener(mouseListener);
		GlobalScreen.getInstance().addNativeMouseMotionListener(mouseListener);

		// Initialize the jnativehook Mouse Wheel Listener
		mouseWheelListener = new GlobalMouseWheelListener(dataGarbageCan, statusConsole);
		GlobalScreen.getInstance().addNativeMouseWheelListener(mouseWheelListener);
		
		// Begin checking for hotkey presses
		Hotkey hotkey = new Hotkey(this);
		keyboardListener.setHotkeyObject(hotkey);
	}

	/**
	 * Adds UI elements (Record, Stop, and Replay buttons, the status JTextArea, and mouse info bar) to the specified panel.
	 * 
	 * @param p	the panel to add the UI elements to
	 */
	public void addUIComponents(JPanel p) {
		// Buttons
		JPanel buttonPanel = new JPanel();
		startRecording = new JButton("Record");
		startRecording.putClientProperty("id",ButtonAction.START_RECORDING);
		startRecording.addActionListener(this);

		stopRecording = new JButton("Stop Recording");
		stopRecording.putClientProperty("id",ButtonAction.STOP_RECORDING);
		stopRecording.addActionListener(this);
		stopRecording.setEnabled(false);

		replay = new JButton("Replay");
		replay.putClientProperty("id", ButtonAction.REPLAY);
		replay.addActionListener(this);

		buttonPanel.add(startRecording);
		buttonPanel.add(stopRecording);
		buttonPanel.add(replay);
		p.add(buttonPanel, BorderLayout.NORTH);

		// Status Area
		statusConsole = new StatusArea(13, 40);
		DefaultCaret caret = (DefaultCaret)statusConsole.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

		JScrollPane scrollPane = new JScrollPane(statusConsole);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		p.add(scrollPane, BorderLayout.SOUTH);
		
		// Mouse Info Bar
		JLabel mousePositionLabel = new JLabel("Position: ");
		mousePositionLabel.setHorizontalAlignment(SwingConstants.LEFT);
		
		mousePositionTextDataLabel = new JLabel();
		mousePositionTextDataLabel.setHorizontalAlignment(SwingConstants.LEFT);
		
		JPanel mousePosition = new JPanel();
		mousePosition.setLayout(new BoxLayout(mousePosition, BoxLayout.X_AXIS));
		mousePosition.add(mousePositionLabel);
		mousePosition.add(mousePositionTextDataLabel);
		
		JLabel mouseColorLabel = new JLabel("Mouse Pixel Color: ");
		mouseColorLabel.setHorizontalAlignment(SwingConstants.LEFT);<commit_msg>Replay button is now disabled on start up.<commit_after>package com.github.thbrown.actionrecorder;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.text.DefaultCaret;

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;

/**
 * This is the main class for the ActionRecorder application.
 * 
 * This applications records mouse and keyboard presses and mouse movement. The recordings can then be played back.
 * @author thbrown
 */
public class Main extends JFrame implements ActionListener, WindowListener {

	// UI objects
	private JPanel mainPanel;
	private JButton startRecording;
	private JButton stopRecording;
	private JButton replay;
	private StatusArea statusConsole;
	private JLabel mousePositionTextDataLabel;
	private JLabel mouseColorTextDataLabel;
	private JPanel mouseColorDataLabel;

	// JNativeHook library objects
	private GlobalKeyboardListener keyboardListener;
	private GlobalMouseListener mouseListener;
	private GlobalMouseWheelListener mouseWheelListener;
	
	// Storages object to store save recorded data
	private Storage dataHolder;
	private Storage dataGarbageCan;
	
	// A handle for the thread used to playback data
	private Playback playbackThread;
	
	// Layout parameters
	private static final int MOUSE_INFO_PANEL_HEIGHT = 25;
	private static final int MOUSE_INFO_PANEL_COLOR_WIDTH = 50;
	private static final int MOUSE_INFO_PANEL_COLOR_TEXT_WIDTH = 85;
	
	public static void main(String[] args) {
		Main m = new Main("ActionRecorder");
		m.setVisible(true);
	}

	public Main(String title) {
		setTitle(title);
		setPreferredSize(new Dimension(500,350));
		setMinimumSize(getPreferredSize());
		this.addWindowListener(this);

		mainPanel = new JPanel();
		this.addUIComponents(mainPanel);
		this.add(mainPanel, BorderLayout.CENTER);
		this.setFocusable(true);
		
		// Create the menu bar.
		JMenuBar menuBar = new JMenuBar();

		// Build the first menu.
		JMenu menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_A);
		menu.getAccessibleContext().setAccessibleDescription("The only menu in this program that has menu items");
		menuBar.add(menu);

		// A group of JMenuItems
		JMenuItem menuItem = new JMenuItem("Exit", KeyEvent.VK_T);
		menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
		menuItem.getAccessibleContext().setAccessibleDescription("This doesn't really do anything");
		menuItem.addActionListener(this);
		menu.add(menuItem);
		
		// Attach the menu to the JFrame
		this.setJMenuBar(menuBar);
		
		// Initialize storage objects, one that saves command data and one that discards it
		dataHolder = new ListStorage(statusConsole);
		dataGarbageCan = new BlackholeStorage();
		
		// Initialize the jnativehook Library
		try {
			GlobalScreen.registerNativeHook();
		} catch (NativeHookException ex) {
			String errorMessage = "Error: There was a problem registering the native hook.";
			statusConsole.append(errorMessage);
			statusConsole.append(ex.getMessage());
			startRecording.setEnabled(true);
			return;
		}

		// Initialize the jnativehook Keyboard Listener
		keyboardListener = new GlobalKeyboardListener(dataGarbageCan, statusConsole);
		GlobalScreen.getInstance().addNativeKeyListener(keyboardListener);

		// Initialize the jnativehook Mouse Click/Movement Listener
		mouseListener = new GlobalMouseListener(dataGarbageCan, statusConsole, this);
		GlobalScreen.getInstance().addNativeMouseListener(mouseListener);
		GlobalScreen.getInstance().addNativeMouseMotionListener(mouseListener);

		// Initialize the jnativehook Mouse Wheel Listener
		mouseWheelListener = new GlobalMouseWheelListener(dataGarbageCan, statusConsole);
		GlobalScreen.getInstance().addNativeMouseWheelListener(mouseWheelListener);
		
		// Begin checking for hotkey presses
		Hotkey hotkey = new Hotkey(this);
		keyboardListener.setHotkeyObject(hotkey);
	}

	/**
	 * Adds UI elements (Record, Stop, and Replay buttons, the status JTextArea, and mouse info bar) to the specified panel.
	 * 
	 * @param p	the panel to add the UI elements to
	 */
	public void addUIComponents(JPanel p) {
		// Buttons
		JPanel buttonPanel = new JPanel();
		startRecording = new JButton("Record");
		startRecording.putClientProperty("id",ButtonAction.START_RECORDING);
		startRecording.addActionListener(this);

		stopRecording = new JButton("Stop Recording");
		stopRecording.putClientProperty("id",ButtonAction.STOP_RECORDING);
		stopRecording.addActionListener(this);
		stopRecording.setEnabled(false);

		replay = new JButton("Replay");
		replay.putClientProperty("id", ButtonAction.REPLAY);
		replay.addActionListener(this);
		replay.setEnabled(false);

		buttonPanel.add(startRecording);
		buttonPanel.add(stopRecording);
		buttonPanel.add(replay);
		p.add(buttonPanel, BorderLayout.NORTH);

		// Status Area
		statusConsole = new StatusArea(13, 40);
		DefaultCaret caret = (DefaultCaret)statusConsole.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

		JScrollPane scrollPane = new JScrollPane(statusConsole);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		p.add(scrollPane, BorderLayout.SOUTH);
		
		// Mouse Info Bar
		JLabel mousePositionLabel = new JLabel("Position: ");
		mousePositionLabel.setHorizontalAlignment(SwingConstants.LEFT);
		
		mousePositionTextDataLabel = new JLabel();
		mousePositionTextDataLabel.setHorizontalAlignment(SwingConstants.LEFT);
		
		JPanel mousePosition = new JPanel();
		mousePosition.setLayout(new BoxLayout(mousePosition, BoxLayout.X_AXIS));
		mousePosition.add(mousePositionLabel);
		mousePosition.add(mousePositionTextDataLabel);
		
		JLabel mouseColorLabel = new JLabel("Mouse Pixel Color: ");
		mouseColorLabel.setHorizontalAlignment(SwingConstants.LEFT);
{'fraction_non_alphanumeric': 0.08917828040514812, 'fraction_numerical': 0.002589292513898408, 'mean_word_length': 5.649113924050633, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '6979303', 'n_tokens_mistral': 4112, 'n_tokens_neox': 3754, 'n_words': 915}