adjCells = treeTentBoard.getAdjacent(cell, TreeTentType.TENT);
diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java
index 70fbea033..b1aa24eca 100644
--- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java
+++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java
@@ -10,6 +10,10 @@
import java.util.Objects;
import javax.swing.*;
+/**
+ * Provides the user interface components for creating a new puzzle in the Legup application.
+ * This package includes classes for displaying dialog boxes to configure and initialize puzzles.
+ */
public class CreatePuzzleDialog extends JDialog {
private HomePanel homePanel;
@@ -17,6 +21,13 @@ public class CreatePuzzleDialog extends JDialog {
private JComboBox gameBox;
private ActionListener gameBoxListener =
new ActionListener() {
+ /**
+ * An ActionListener that handles changes in the drop-down menu for selecting puzzle types.
+ * When a new item is selected in the drop-down menu, this listener updates the visibility of
+ * the text input area and the row/column input fields based on the selected puzzle type.
+ * If "ShortTruthTable" is selected, the text input area is shown and the row/column fields are hidden.
+ * For other puzzle types, the row/column fields are shown and the text input area is hidden.
+ */
@Override
public void actionPerformed(ActionEvent e) {
JComboBox comboBox = (JComboBox) e.getSource();
@@ -57,9 +68,7 @@ public void actionPerformed(ActionEvent e) {
*/
@Override
public void actionPerformed(ActionEvent ae) {
- String game =
- Config.convertDisplayNameToClassName(
- (String) gameBox.getSelectedItem());
+ String game = getGame();
// Check if all 3 TextFields are filled
if (game.equals("ShortTruthTable") && textArea.getText().isEmpty()) {
@@ -68,8 +77,8 @@ public void actionPerformed(ActionEvent ae) {
}
if (!game.equals("ShortTruthTable")
&& (game.isEmpty()
- || rows.getText().isEmpty()
- || columns.getText().isEmpty())) {
+ || getRows().isEmpty()
+ || getColumns().isEmpty())) {
System.out.println("Unfilled fields");
return;
}
@@ -81,8 +90,8 @@ public void actionPerformed(ActionEvent ae) {
} else {
homePanel.openEditorWithNewPuzzle(
game,
- Integer.valueOf(rows.getText()),
- Integer.valueOf(columns.getText()));
+ Integer.valueOf(getRows()),
+ Integer.valueOf(getColumns()));
}
setVisible(false);
} catch (IllegalArgumentException e) {
@@ -106,6 +115,12 @@ public void actionPerformed(ActionEvent e) {
}
};
+ /**
+ * Constructs a new CreatePuzzleDialog
+ *
+ * @param parent the parent frame of the dialog
+ * @param homePanel the home panel where the created puzzle will be added
+ */
public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) {
super(parent, true);
@@ -184,6 +199,10 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) {
cancel.addActionListener(cursorPressedCancel);
}
+ /**
+ * Initializes the puzzle options available for selection in the dialog.
+ * The options are retrieved from the game board facade and sorted alphabetically.
+ */
public void initPuzzles() {
this.games =
GameBoardFacade.getInstance()
@@ -194,7 +213,12 @@ public void initPuzzles() {
gameBox = new JComboBox(this.games);
}
- // ^This method seems useless and never got covered
+
+ /**
+ * Handles the action events for the dialog, including interactions with the Ok and Cancel buttons
+ *
+ * @param e The action event to be processed
+ */
public void actionPerformed(ActionEvent e) {
if (e.getSource() == ok) {
String game = Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem());
@@ -211,9 +235,7 @@ public void actionPerformed(ActionEvent e) {
}
this.setVisible(false);
} catch (IllegalArgumentException exception) {
- // Don't do anything. This is here to prevent the dialog from closing if the
- // dimensions are
- // invalid.
+ // Do nothing. This is here to prevent the dialog from closing if the dimensions are invalid.
}
} else {
if (e.getSource() == cancel) {
@@ -223,4 +245,38 @@ public void actionPerformed(ActionEvent e) {
}
}
}
+
+ /**
+ * Retrieves the selected game from the combo box
+ *
+ * @return the class name of the selected game
+ */
+ public String getGame() {
+ return Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem());
+ }
+
+ /**
+ * Retrieves the number of rows specified in the dialog
+ *
+ * @return the number of rows as a string
+ */
+ public String getRows() {
+ return rows.getText();
+ }
+
+ /**
+ * Retrieves the number of columns specified in the dialog
+ *
+ * @return the number of columns as a string
+ */
+ public String getColumns() {
+ return columns.getText();
+ }
+
+ /**
+ * Retrieves the text entered in the text area, split by new lines.
+ *
+ * @return an array of strings, each representing as a line of text
+ */
+ public String[] getTextArea() { return textArea.getText().split("\n"); }
}
diff --git a/src/main/java/edu/rpi/legup/ui/DynamicView.java b/src/main/java/edu/rpi/legup/ui/DynamicView.java
index 8d3024c86..344885783 100644
--- a/src/main/java/edu/rpi/legup/ui/DynamicView.java
+++ b/src/main/java/edu/rpi/legup/ui/DynamicView.java
@@ -16,6 +16,10 @@
import javax.swing.*;
import javax.swing.event.ChangeEvent;
+/**
+ * A JPanel that provides a dynamic view with zooming capabilities for different types of content.
+ * This class supports views such as game boards or proof trees, allowing users to zoom in and out.
+ */
public class DynamicView extends JPanel {
private ScrollView scrollView;
@@ -29,6 +33,12 @@ public class DynamicView extends JPanel {
private static final Font INFO_FONT = MaterialFonts.REGULAR;
private static final Color INFO_COLOR = MaterialColors.GRAY_900;
+ /**
+ * Constructs a new DynamicView with the specified ScrollView and view type
+ *
+ * @param scrollView the ScrollView that provides the content to be displayed and zoomed
+ * @param type the type of dynamic view to set up (e.g., BOARD or PROOF_TREE)
+ */
public DynamicView(ScrollView scrollView, DynamicViewType type) {
this.scrollView = scrollView;
@@ -185,34 +195,65 @@ public void componentResized(ComponentEvent e) {
return zoomWrapper;
}
+ /**
+ * Gets the ScrollView component associated with this DynamicView
+ *
+ * @return the ScrollView component
+ */
public ScrollView getScrollView() {
return this.scrollView;
}
+ /**
+ * Gets the zoom wrapper that contains the zooming controls
+ *
+ * @return the zoom wrapper with zooming controls
+ */
public JPanel getZoomWrapper() {
return this.zoomWrapper;
}
+ /**
+ * Gets the zoomer that contains the zoomer component
+ *
+ * @return the zoomer with the zoomer component
+ */
public JPanel getZoomer() {
return this.zoomer;
}
+ /**
+ * Updates the status label with an informational message
+ *
+ * @param message the informational message to display
+ */
public void updateInfo(String message) {
status.setFont(INFO_FONT);
status.setForeground(INFO_COLOR);
status.setText(message);
}
+ /**
+ * Updates the status label with an error message
+ *
+ * @param message the error message to display
+ */
public void updateError(String message) {
status.setFont(ERROR_FONT);
status.setForeground(ERROR_COLOR);
status.setText(message);
}
+ /**
+ * Clears the status label
+ */
public void resetStatus() {
status.setText("");
}
+ /**
+ * Resets the view to its default state and zooms the content to fit the screen
+ */
public void reset() {
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
Board board1 = GameBoardFacade.getInstance().getBoard();
@@ -221,6 +262,9 @@ public void reset() {
this.getScrollView().zoomFit();
}
+ /**
+ * Fits the board view to the screen
+ */
protected void fitBoardViewToScreen() {
scrollView.zoomFit();
}
diff --git a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java
index 8c2f285cd..d161f5b9c 100644
--- a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java
+++ b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java
@@ -1,5 +1,13 @@
package edu.rpi.legup.ui;
+/**
+ * An enumeration representing the different types of dynamic views supported by the application.
+ * The two types of views are:
+ *
+ * - {@code BOARD} - Represents a dynamic view of a game board
+ * - {@code PROOF_TREE} - Represents a dynamic view of a proof tree
+ *
+ */
public enum DynamicViewType {
BOARD,
PROOF_TREE
diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java
index 11f51eb0e..f12ffdbf0 100644
--- a/src/main/java/edu/rpi/legup/ui/HomePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java
@@ -25,6 +25,12 @@
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
+/**
+ * The {@code HomePanel} class represents the home panel of the LEGUP application.
+ * This panel provides buttons for functionalities of opening the proof editor,
+ * opening the puzzle editor, and performing batch grading. It also includes a menu bar with
+ * options for preferences.
+ */
public class HomePanel extends LegupPanel {
private static final Logger LOGGER = LogManager.getLogger(HomePanel.class.getName());
private LegupUI legupUI;
@@ -36,44 +42,37 @@ public class HomePanel extends LegupPanel {
private final int buttonSize = 100;
+ /**
+ * Initialize the proof solver to an empty panel with no puzzle
+ */
private ActionListener openProofListener =
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- Object[] items = legupUI.getProofEditor().promptPuzzle();
- if (items == null) {
- // The attempt to prompt a puzzle ended gracefully (cancel)
- return;
- }
- String fileName = (String) items[0];
- File puzzleFile = (File) items[1];
- legupUI.getProofEditor().loadPuzzle(fileName, puzzleFile);
- }
- };
-
- private ActionListener openPuzzleListener =
- new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- Object[] items = legupUI.getPuzzleEditor().promptPuzzle();
- if (items == null) {
- // The attempt to prompt a puzzle ended gracefully (cancel)
- return;
- }
- String fileName = (String) items[0];
- File puzzleFile = (File) items[1];
- legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile);
+ legupUI.getProofEditor().loadPuzzle("", null);
}
};
- public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) {
+ /**
+ * Constructs a {@code HomePanel} with the specified {@code JFrame} and {@code LegupUI}.
+ *
+ * @param frame the main application frame
+ * @param legupUI the LEGUP user interface
+ */
+ public HomePanel(JFrame frame, LegupUI legupUI) {
this.legupUI = legupUI;
this.frame = frame;
setLayout(new GridLayout(1, 2));
+ setPreferredSize(new Dimension(440, 250));
initText();
initButtons();
}
+ /**
+ * Creates and returns the menu bar for this panel
+ *
+ * @return the menu bar
+ */
public JMenuBar getMenuBar() {
this.menuBar = new JMenuBar();
JMenu settings = new JMenu("Settings");
@@ -102,23 +101,37 @@ public JMenuBar getMenuBar() {
return this.menuBar;
}
+ /**
+ * Makes the panel visible and sets the menu bar of the frame
+ */
@Override
public void makeVisible() {
render();
frame.setJMenuBar(this.getMenuBar());
}
+ /**
+ * Resizes the provided icon to the specified width and height
+ *
+ * @param icon the icon to resize
+ * @param width the target width
+ * @param height the target height
+ * @return the resized icon
+ */
private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) {
Image image = icon.getImage();
Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
return new ImageIcon(resizedImage);
}
+ /**
+ * Initializes the buttons for this panel
+ */
private void initButtons() {
- this.buttons = new JButton[4];
+ this.buttons = new JButton[3];
this.buttons[0] =
- new JButton("Solve Puzzle") {
+ new JButton("Puzzle Solver") {
{
setSize(buttonSize, buttonSize);
setMaximumSize(getSize());
@@ -136,7 +149,7 @@ private void initButtons() {
this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener));
this.buttons[1] =
- new JButton("Create Puzzle") {
+ new JButton("Puzzle Editor") {
{
setSize(buttonSize, buttonSize);
setMaximumSize(getSize());
@@ -150,35 +163,17 @@ private void initButtons() {
this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize));
this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER);
this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM);
- this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog());
-
- this.buttons[2] =
- new JButton("Edit Puzzle") {
- {
- setSize(buttonSize, buttonSize);
- setMaximumSize(getSize());
- }
- };
- URL button2IconLocation =
- ClassLoader.getSystemClassLoader()
- .getResource("edu/rpi/legup/images/Legup/homepanel/puzzle_file.png");
- ImageIcon button2Icon = new ImageIcon(button2IconLocation);
- this.buttons[2].setFocusPainted(false);
- this.buttons[2].setIcon(resizeButtonIcon(button2Icon, this.buttonSize, this.buttonSize));
- this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER);
- this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM);
- this.buttons[2].addActionListener(
- CursorController.createListener(this, openPuzzleListener)); // PLACEHOLDER
+ this.buttons[1].addActionListener(l -> this.openPuzzleEditorDialog());
for (int i = 0; i < this.buttons.length - 1; i++) { // -1 to avoid the batch grader button
this.buttons[i].setBounds(200, 200, 700, 700);
}
- this.buttons[3] = new JButton("Batch Grader");
- this.buttons[3].setFocusPainted(false);
- this.buttons[3].setHorizontalTextPosition(AbstractButton.CENTER);
- this.buttons[3].setVerticalTextPosition(AbstractButton.BOTTOM);
+ this.buttons[2] = new JButton("Batch Grader");
+ this.buttons[2].setFocusPainted(false);
+ this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER);
+ this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM);
- this.buttons[3].addActionListener(
+ this.buttons[2].addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -192,6 +187,10 @@ public void actionPerformed(ActionEvent e) {
});
}
+ /**
+ * Opens a folder chooser dialog and grades puzzles in the selected folder.
+ * The results are written to a CSV file.
+ */
public void checkFolder() {
GameBoardFacade facade = GameBoardFacade.getInstance();
/*
@@ -272,13 +271,17 @@ public void checkFolder() {
}
} catch (IOException ex) {
LOGGER.error(ex.getMessage());
- this.buttons[3].addActionListener((ActionEvent e) -> use_xml_to_check());
+ this.buttons[2].addActionListener((ActionEvent e) -> use_xml_to_check());
}
}
/**
- * @effect batch grade using .xml parser - go through a collection of files and report their
- * "solved?" status
+ * Processes XML files within a selected directory and generates a CSV report on their "solved?" status.
+ * The method allows the user to select a directory, and evaluates each XML file for a "solved?" status.
+ * Results are saved in a "result.csv" file.
+ *
+ * @effect Selects a directory, processes each XML file to check for "solved?" status,
+ * and writes results to "result.csv". Opens the CSV file upon completion.
*/
private void use_xml_to_check() {
/* Select a folder, go through each .xml file in the subfolders, look for "isSolved" flag */
@@ -477,6 +480,10 @@ public void endDocument() throws SAXException {
}
}
+ /**
+ * Initializes the text labels for the user interface.
+ * Sets up labels for welcome message, led by Bram, and version information.
+ */
private void initText() {
// TODO: add version text after auto-changing version label is implemented. (text[2] =
// version)
@@ -498,11 +505,14 @@ private void initText() {
this.text[1] = credits;
}
+ /**
+ * Renders the user interface components
+ */
private void render() {
this.removeAll();
this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
- this.legupUI.setTitle("LEGUP: A Better Way to Learn Formal Logic");
+ this.legupUI.setTitle("LEGUP: A Better Way To Learn Formal Logic");
JPanel buttons = new JPanel();
buttons.add(Box.createRigidArea(new Dimension(5, 0)));
@@ -510,11 +520,8 @@ private void render() {
buttons.add(Box.createRigidArea(new Dimension(5, 0)));
buttons.add(this.buttons[1]);
buttons.add(Box.createRigidArea(new Dimension(5, 0)));
- buttons.add(this.buttons[2]);
- buttons.add(Box.createRigidArea(new Dimension(5, 0)));
-
JPanel batchGraderButton = new JPanel();
- batchGraderButton.add(this.buttons[3]);
+ batchGraderButton.add(this.buttons[2]);
batchGraderButton.setAlignmentX(Component.CENTER_ALIGNMENT);
this.add(Box.createRigidArea(new Dimension(0, 5)));
@@ -526,11 +533,28 @@ private void render() {
this.add(Box.createRigidArea(new Dimension(0, 5)));
}
- private void openNewPuzzleDialog() {
- CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, this);
- cpd.setVisible(true);
+ /**
+ * Opens the puzzle editor dialog with no selected puzzle, leaving a blank panel
+ *
+ * @throws IllegalArgumentException if the configuration parameters are invalid (should never happen)
+ */
+ private void openPuzzleEditorDialog() {
+ String game = "";
+ int r = 0;
+ int c = 0;
+
+ try {
+ this.openEditorWithNewPuzzle(game, r, c);
+ } catch (IllegalArgumentException e) {
+ System.out.println("Failed to open editor with new puzzle");
+ e.printStackTrace(System.out);
+ }
}
+ /**
+ * Opens a dialog to select a directory, recursively processes the directory to grade puzzles,
+ * and generates a CSV report of the grading results.
+ */
private void checkProofAll() {
/*
* Select dir to grade; recursively grade sub-dirs using traverseDir()
@@ -574,6 +598,14 @@ private void checkProofAll() {
JOptionPane.showMessageDialog(null, "Batch grading complete.");
}
+ /**
+ * Recursively traverses directories to grade puzzles and writes results to a CSV file
+ *
+ * @param folder the folder to traverse
+ * @param writer the BufferedWriter to write results to the CSV file
+ * @param path the current path within the directory structure
+ * @throws IOException if an I/O error occurs while writing to the CSV file
+ */
private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException {
// Recursively traverse directory
GameBoardFacade facade = GameBoardFacade.getInstance();
@@ -626,28 +658,48 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws
}
}
+ /**
+ * Opens the puzzle editor for the specified puzzle with the specified dimensions
+ *
+ * @param game the name of the game
+ * @param rows the number of rows in the puzzle
+ * @param columns the number of columns in the puzzle
+ * @throws IllegalArgumentException if the dimensions are invalid
+ */
public void openEditorWithNewPuzzle(String game, int rows, int columns)
throws IllegalArgumentException {
- // Validate the dimensions
- GameBoardFacade facade = GameBoardFacade.getInstance();
- boolean isValidDimensions = facade.validateDimensions(game, rows, columns);
- if (!isValidDimensions) {
- JOptionPane.showMessageDialog(
- null,
- "The dimensions you entered are invalid. Please double check \n"
- + "the number of rows and columns and try again.",
- "ERROR: Invalid Dimensions",
- JOptionPane.ERROR_MESSAGE);
- throw new IllegalArgumentException("ERROR: Invalid dimensions given");
+ if (game.equals("")) {
+ this.legupUI.displayPanel(2);
+ this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns);
+ }
+ else {
+ // Validate the dimensions
+ GameBoardFacade facade = GameBoardFacade.getInstance();
+ boolean isValidDimensions = facade.validateDimensions(game, rows, columns);
+ if (!isValidDimensions) {
+ JOptionPane.showMessageDialog(
+ null,
+ "The dimensions you entered are invalid. Please double check \n"
+ + "the number of rows and columns and try again.",
+ "ERROR: Invalid Dimensions",
+ JOptionPane.ERROR_MESSAGE);
+ throw new IllegalArgumentException("ERROR: Invalid dimensions given");
+ }
+
+ if (this.legupUI == null) {
+ System.err.println("Error: legupUI is null in HomePanel");
+ return;
+ }
+
+ // Set game type on the puzzle editor
+ this.legupUI.displayPanel(2);
+ this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns);
}
- // Set game type on the puzzle editor
- this.legupUI.displayPanel(2);
- this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns);
}
/**
- * Opens the puzzle editor for the specified game with the given statements
+ * Opens the puzzle editor for the specified puzzle with the given statements
*
* @param game a String containing the name of the game
* @param statements an array of statements
diff --git a/src/main/java/edu/rpi/legup/ui/LegupPanel.java b/src/main/java/edu/rpi/legup/ui/LegupPanel.java
index d16167b3d..38c44cbe4 100644
--- a/src/main/java/edu/rpi/legup/ui/LegupPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/LegupPanel.java
@@ -2,9 +2,18 @@
import javax.swing.*;
+/**
+ * An abstract base class for panels in the LEGUP application.
+ * This class extends {@link JPanel} and defines common properties and methods
+ * for all panels in the LEGUP user interface
+ * (currently only implements toolbar scale)
+ */
public abstract class LegupPanel extends JPanel {
/** Alerts panel that it will be going visible now */
protected final int TOOLBAR_ICON_SCALE = 40;
+ /**
+ * Abstract method to make the panel visible
+ */
public abstract void makeVisible();
}
diff --git a/src/main/java/edu/rpi/legup/ui/LegupUI.java b/src/main/java/edu/rpi/legup/ui/LegupUI.java
index eb8b1663c..30857f05f 100644
--- a/src/main/java/edu/rpi/legup/ui/LegupUI.java
+++ b/src/main/java/edu/rpi/legup/ui/LegupUI.java
@@ -14,6 +14,11 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+/**
+ * The main user interface class for the LEGUP application.
+ * This class extends {@link JFrame} and implements {@link WindowListener}
+ * to manage the overall window and provide functionality for displaying various panels.
+ */
public class LegupUI extends JFrame implements WindowListener {
private static final Logger LOGGER = LogManager.getLogger(LegupUI.class.getName());
@@ -36,7 +41,7 @@ public static String getOS() {
return os;
}
- /** LegupUI Constructor - creates a new LegupUI to setup the menu and toolbar */
+ /** LegupUI Constructor - creates a new LegupUI to set up the menu and toolbar */
public LegupUI() {
setTitle("LEGUP");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -91,17 +96,27 @@ public void keyTyped(KeyEvent e) {
setVisible(true);
}
+ /**
+ * Initializes the panels used in the UI.
+ * Sets up the layout and adds panels to the window.
+ */
private void initPanels() {
window = new JPanel();
window.setLayout(new BorderLayout());
add(window);
panels = new LegupPanel[3];
- panels[0] = new HomePanel(this.fileDialog, this, this);
+ panels[0] = new HomePanel(this, this);
panels[1] = new ProofEditorPanel(this.fileDialog, this, this);
panels[2] = new PuzzleEditorPanel(this.fileDialog, this, this);
}
+ /**
+ * Displays the specified panel
+ *
+ * @param option the index of the panel to display
+ * @throws InvalidParameterException if the option is out of range
+ */
protected void displayPanel(int option) {
if (option > panels.length || option < 0) {
throw new InvalidParameterException("Invalid option");
@@ -115,29 +130,31 @@ protected void displayPanel(int option) {
repaint();
}
+ /**
+ * Gets the ProofEditorPanel instance
+ *
+ * @return the ProofEditorPanel
+ */
public ProofEditorPanel getProofEditor() {
return (ProofEditorPanel) panels[1];
}
+ /**
+ * Gets the PuzzleEditorPanel instance
+ *
+ * @return the PuzzleEditorPanel
+ */
public PuzzleEditorPanel getPuzzleEditor() {
return (PuzzleEditorPanel) panels[2];
}
+ /**
+ * Repaints the tree view in the proof editor.
+ */
public void repaintTree() {
getProofEditor().repaintTree();
}
- private void directions() {
- JOptionPane.showMessageDialog(
- null,
- "For every move you make, you must provide a rules for it (located in the Rules"
- + " panel).\n"
- + "While working on the edu.rpi.legup.puzzle, you may click on the \"Check\""
- + " button to test your proof for correctness.",
- "Directions",
- JOptionPane.PLAIN_MESSAGE);
- }
-
public void showStatus(String status, boolean error) {
showStatus(status, error, 1);
}
@@ -150,8 +167,13 @@ public void showStatus(String status, boolean error, int timer) {
// TODO: implement
}
- // ask to edu.rpi.legup.save current proof
- public boolean noquit(String instr) {
+ /**
+ * Prompts the user to confirm if they want to exit LEGUP
+ *
+ * @param instr the prompt message
+ * @return true if the user chooses not to quit, false otherwise
+ */
+ public boolean exit(String instr) {
int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION);
return n != JOptionPane.YES_OPTION;
}
@@ -161,7 +183,7 @@ public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {
if (GameBoardFacade.getInstance().getHistory().getIndex() > -1) {
- if (noquit("Exiting LEGUP?")) {
+ if (exit("Exiting LEGUP?")) {
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
} else {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
@@ -183,22 +205,47 @@ public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
+ /**
+ * Gets the BoardView instance from the proof editor
+ *
+ * @return the BoardView
+ */
public BoardView getBoardView() {
return getProofEditor().getBoardView();
}
+ /**
+ * Gets the BoardView instance from the puzzle editor
+ *
+ * @return the BoardView
+ */
public BoardView getEditorBoardView() {
return getPuzzleEditor().getBoardView();
}
+ /**
+ * Gets the DynamicView instance from the proof editor
+ *
+ * @return the DynamicView
+ */
public DynamicView getDynamicBoardView() {
return getProofEditor().getDynamicBoardView();
}
+ /**
+ * Gets the DynamicView instance from the puzzle editor.
+ *
+ * @return the DynamicView
+ */
public DynamicView getEditorDynamicBoardView() {
return getPuzzleEditor().getDynamicBoardView();
}
+ /**
+ * Gets the TreePanel instance from the proof editor
+ *
+ * @return the TreePanel
+ */
public TreePanel getTreePanel() {
return getProofEditor().getTreePanel();
}
diff --git a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java
index f703ffcbc..a6501e2a0 100644
--- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java
+++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java
@@ -15,6 +15,11 @@
import javax.swing.JLabel;
import javax.swing.JTextField;
+/**
+ * A dialog for selecting a game.
+ * This class extends {@link JDialog} and implements {@link ActionListener}
+ * to handle user interactions for selecting a game type and puzzle file.
+ */
public class PickGameDialog extends JDialog implements ActionListener {
JLabel gameLabel = new JLabel("Game:");
String[] games;
@@ -106,6 +111,10 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) {
c.add(autojustifyCheckBox);
}
+ /**
+ * Initializes the available games and puzzles.
+ * Populates the {@link JComboBox} with game types and sets up the puzzle options.
+ */
public void initPuzzles() {
Object[] o = GameBoardFacade.getInstance().getConfig().getPuzzleClassNames().toArray();
@@ -128,14 +137,31 @@ public void initPuzzles() {
gameBox = new JComboBox(games);
}
+ /**
+ * Gets the selected puzzle file path
+ *
+ * @return the puzzle file path as a String
+ */
public String getPuzzle() {
return puzzleBox.getText();
}
+ /**
+ * Returns the selected puzzle
+ *
+ * @return the selected puzzle as a String
+ */
public String getGame() {
return (String) gameBox.getSelectedItem();
}
+ /**
+ * Handles action events for the dialog components.
+ * Responds to user interactions such as selecting a puzzle, choosing a puzzle file,
+ * and pressing the 'Ok' or 'Cancel' buttons.
+ *
+ * @param e the action event
+ */
public void actionPerformed(ActionEvent e) {
if (e.getSource() == gameBox) {
int index = gameBox.getSelectedIndex();
diff --git a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java
index 475f4bb68..c8639f796 100644
--- a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java
+++ b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java
@@ -17,6 +17,12 @@
import javax.imageio.ImageIO;
import javax.swing.*;
+/**
+ * A dialog for managing user preferences in the LEGUP application.
+ * This dialog allows users to configure various settings such as screen mode,
+ * update preferences, work directory path, and specific features related to board and tree views.
+ * Users can access this dialog from the home screen or proof editor.
+ */
public class PreferencesDialog extends JDialog {
private RuleFrame rulesFrame;
@@ -47,12 +53,24 @@ public class PreferencesDialog extends JDialog {
}
}
+ /**
+ * Creates a new instance of PreferencesDialog for the proof editor
+ *
+ * @param frame the parent frame
+ * @param rules the RuleFrame associated with the proof editor
+ * @return a new instance of PreferencesDialog
+ */
public static PreferencesDialog CreateDialogForProofEditor(Frame frame, RuleFrame rules) {
PreferencesDialog p = new PreferencesDialog(frame);
p.rulesFrame = rules;
return p;
}
+ /**
+ * Constructs a PreferencesDialog
+ *
+ * @param frame the parent frame
+ */
public PreferencesDialog(Frame frame) {
super(frame);
@@ -102,6 +120,11 @@ public PreferencesDialog(Frame frame) {
setVisible(true);
}
+ /**
+ * Toggles between dark mode and light mode based on the given preferences
+ *
+ * @param prefs the LegupPreferences instance holding user preferences
+ */
private void toggleDarkMode(LegupPreferences prefs) {
try {
if (Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))) {
@@ -115,6 +138,11 @@ private void toggleDarkMode(LegupPreferences prefs) {
}
}
+ /**
+ * Creates the general preferences tab
+ *
+ * @return a JScrollPane containing the general preferences panel
+ */
private JScrollPane createGeneralTab() {
LegupPreferences prefs = LegupPreferences.getInstance();
JScrollPane scrollPane = new JScrollPane();
@@ -335,6 +363,15 @@ private JScrollPane createPuzzleTab(Puzzle puzzle) {
return scrollPane;
}
+ /**
+ * Creates a JPanel that represents a single row for a rule in the rule list.
+ * Each row displays the rule's name and an area for showing keyboard shortcuts
+ * associated with the rule. The keyboard shortcuts are dynamically updated based
+ * on user input.
+ *
+ * @param rule the rule object to be displayed
+ * @return a JPanel representing the row for the rule
+ */
private JPanel createRuleRow(Rule rule) {
JPanel ruleRow = new JPanel();
ruleRow.setLayout(new BorderLayout());
@@ -387,6 +424,14 @@ public void keyPressed(KeyEvent e) {
return ruleRow;
}
+ /**
+ * Creates a JPanel containing a left-aligned label with the specified text.
+ * This label is typically used for section headings or descriptive text in the
+ * preferences dialog.
+ *
+ * @param text the text to be displayed on the label
+ * @return a JPanel containing the left-aligned label
+ */
private JPanel createLeftLabel(String text) {
JPanel labelRow = new JPanel();
labelRow.setLayout(new BorderLayout());
@@ -400,12 +445,24 @@ private JPanel createLeftLabel(String text) {
return labelRow;
}
+ /**
+ * Creates a JSeparator with a maximum height of 5 pixels.
+ * This separator is used to visually divide sections in the preferences dialog.
+ *
+ * @return a JSeparator with a fixed height
+ */
private JSeparator createLineSeparator() {
JSeparator separator = new JSeparator();
separator.setMaximumSize(new Dimension(Integer.MAX_VALUE, 5));
return separator;
}
+ /**
+ * Applies the current user preferences and updates the associated components.
+ * This method retrieves user preferences from the dialog's components and stores
+ * them in the {@link LegupPreferences} instance. It also updates the rule panels
+ * in the rules frame if it is not null.
+ */
public void applyPreferences() {
LegupPreferences prefs = LegupPreferences.getInstance();
prefs.setUserPref(LegupPreferences.WORK_DIRECTORY, workDirectory.getText());
diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java
index 645a2c0d7..88c1ee427 100644
--- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java
@@ -17,6 +17,7 @@
import edu.rpi.legup.ui.boardview.BoardView;
import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame;
import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel;
+import edu.rpi.legup.ui.proofeditorui.treeview.TreeTransitionView;
import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection;
import edu.rpi.legup.user.Submission;
import java.awt.*;
@@ -36,6 +37,14 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+/**
+ * {@code ProofEditorPanel} is a panel that serves as the main user interface
+ * component for the proof editing functionality of LEGUP. It provides
+ * the graphical components and interactive elements necessary for editing and managing
+ * proofs, including toolbars, menus, and views for different aspects of proof editing.
+ * It also manages interactions with the rest of the application and updates the UI
+ * based on user actions and application state changes.
+ */
public class ProofEditorPanel extends LegupPanel implements IHistoryListener {
private static final Logger LOGGER = LogManager.getLogger(ProofEditorPanel.class.getName());
private JMenuBar mBar;
@@ -46,8 +55,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener {
private DynamicView dynamicBoardView;
private JSplitPane topHalfPanel, mainPanel;
private TitledBorder boardBorder;
-
- private JButton[] toolBarButtons;
+ private JButton[] toolBar1Buttons;
+ private JButton[] toolBar2Buttons;
private JMenu file;
private JMenuItem newPuzzle,
resetPuzzle,
@@ -67,7 +76,8 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener {
private JMenu about, help;
private JMenuItem helpLegup, aboutLegup;
- private JToolBar toolBar;
+ private JToolBar toolBar1;
+ private JToolBar toolBar2;
private BoardView boardView;
private JFileChooser folderBrowser;
@@ -81,7 +91,6 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener {
public static final int IMD_FEEDBACK = 32;
public static final int INTERN_RO = 64;
public static final int AUTO_JUST = 128;
- static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8};
private static final String[] PROFILES = {
"No Assistance",
"Rigorous Proof",
@@ -111,6 +120,13 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener {
protected JMenuItem testAI = new JMenuItem("Test AI!");
protected JMenuItem hintAI = new JMenuItem("Hint");
+ /**
+ * Constructs a new {@code ProofEditorPanel} with the specified parameters
+ *
+ * @param fileDialog the {@code FileDialog} used for file operations
+ * @param frame the {@code JFrame} that contains this panel
+ * @param legupUI the {@code LegupUI} instance managing the user interface
+ */
public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) {
this.fileDialog = fileDialog;
this.frame = frame;
@@ -119,22 +135,44 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) {
setPreferredSize(new Dimension(800, 700));
}
+ /**
+ * Makes the panel visible by setting up the toolbar and content components.
+ * This method also sets the menu bar of the frame to the one used by this panel.
+ */
@Override
public void makeVisible() {
this.removeAll();
- setupToolBar();
+ setupToolBar1();
setupContent();
frame.setJMenuBar(getMenuBar());
}
+ /**
+ * Constructs and returns the {@code JMenuBar} for this panel.
+ * It populates it with various {@code JMenu} and {@code JMenuItem} components related
+ * to file operations, editing, viewing, and proof management.
+ * The menu bar includes:
+ *
+ * - {@code File} menu with options to open a new puzzle, reset the puzzle, save the proof,
+ * access preferences, and exit the editor.
+ * - {@code Edit} menu with options for undo, redo, and fitting the board or tree to the screen.
+ * - {@code Proof} menu with options for adding, deleting, merging, collapsing elements,
+ * and toggling settings related to rule applications and feedback.
+ * - {@code About} menu with options to view information about the application and access help resources.
+ *
+ *
+ * Accelerator keys are set based on the operating system (Mac or non-Mac).
+ *
+ * @return the {@code JMenuBar} instance containing the menus and menu items for this panel
+ */
public JMenuBar getMenuBar() {
if (mBar != null) return mBar;
mBar = new JMenuBar();
file = new JMenu("File");
newPuzzle = new JMenuItem("Open");
- resetPuzzle = new JMenuItem("Reset Puzzle");
+ resetPuzzle = new JMenuItem("Reset");
// genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle
// generator
saveProofAs = new JMenuItem("Save As"); // create a new file to save
@@ -310,6 +348,7 @@ public JMenuBar getMenuBar() {
} else {
resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK));
}
+
file.addSeparator();
file.add(saveProofAs);
@@ -457,6 +496,10 @@ public void actionPerformed(ActionEvent e) {
return mBar;
}
+ /**
+ * Clears the current puzzle, resets the UI to display the initial panel,
+ * and nullifies the references to the tree panel and board view.
+ */
public void exitEditor() {
// Wipes the puzzle entirely as if LEGUP just started
GameBoardFacade.getInstance().clearPuzzle();
@@ -465,7 +508,13 @@ public void exitEditor() {
boardView = null;
}
- // File opener
+ /**
+ * Opens a file chooser dialog allowing the user to select a directory. It uses the user's
+ * preferred directory or the last saved path if available. The selected directory is used
+ * to set the new working directory.
+ *
+ * @return an array containing the file name and the selected file, or {@code null} if the operation was canceled
+ */
public Object[] promptPuzzle() {
GameBoardFacade facade = GameBoardFacade.getInstance();
if (facade.getBoard() != null) {
@@ -505,9 +554,16 @@ public Object[] promptPuzzle() {
return null;
}
+ System.out.println(preferences.getSavedPath());
return new Object[] {fileName, puzzleFile};
}
+ /**
+ * Calls {@link #promptPuzzle()} to get the file information and then loads the puzzle using
+ * the provided file name and file object. Updates the frame title to reflect the puzzle name.
+ * If the file is not valid or an error occurs, an error message is shown, and the user is
+ * prompted to try loading another puzzle.
+ */
public void loadPuzzle() {
Object[] items = promptPuzzle();
// Return if items == null (cancel)
@@ -519,7 +575,19 @@ public void loadPuzzle() {
loadPuzzle(fileName, puzzleFile);
}
+ /**
+ * Attempts to load a puzzle from the given file. If successful, it updates the
+ * UI to display the puzzle and changes the frame title to include the puzzle name. If the
+ * file is invalid or cannot be read, it shows an appropriate error message and prompts the
+ * user to try loading another puzzle.
+ *
+ * @param fileName the name of the file to load
+ * @param puzzleFile the file object representing the puzzle file
+ */
public void loadPuzzle(String fileName, File puzzleFile) {
+ if (puzzleFile == null && fileName.equals("")) {
+ legupUI.displayPanel(1);
+ }
if (puzzleFile != null && puzzleFile.exists()) {
try {
legupUI.displayPanel(1);
@@ -554,7 +622,11 @@ public void loadPuzzle(String fileName, File puzzleFile) {
}
}
- /** save the proof in the current file */
+ /**
+ * Uses the current puzzle and its associated exporter to save the puzzle data
+ * to the file currently being used. If the puzzle or exporter is null, or if an error occurs
+ * during export, the method will catch the exception and print the stack trace.
+ */
private void direct_save() {
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
if (puzzle == null) {
@@ -574,7 +646,11 @@ private void direct_save() {
}
}
- /** Create a new file and save proof to it */
+ /**
+ * Opens a file chooser dialog for the user to select a directory. The chosen directory is used
+ * to determine where the puzzle file will be saved. If an exporter is available, it will be used
+ * to export the puzzle data to the selected path.
+ */
private void saveProofAs() {
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
if (puzzle == null) {
@@ -612,6 +688,11 @@ private void saveProofAs() {
}
// Hyperlink for help button; links to wiki page for tutorials
+ /**
+ * Opens the default web browser to a help page related to the type of puzzle currently being used.
+ * The URL is chosen based on the name of the puzzle. If the puzzle type is not recognized, a general
+ * tutorial page is opened.
+ */
private void helpTutorial() {
// redirecting to certain help link in wiki
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
@@ -639,16 +720,14 @@ private void helpTutorial() {
default:
url = "https://github.com/Bram-Hub/Legup/wiki/LEGUP-Tutorial";
}
- Runtime rt = Runtime.getRuntime();
try {
- // rt.exec("rundll32 url.dll,FileProtocolHandler "+url);
java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
} catch (IOException e) {
e.printStackTrace();
}
}
- // add the new function need to implement
+ // unfinished
public void add_drop() {
// add the mouse event then we can use the new listener to implement and
// we should create a need jbuttom for it to ship the rule we select.
@@ -665,7 +744,11 @@ public void actionPerformed(ActionEvent e) {
panel.add(moveing_buttom);
}
- // Quick save proof to the current file with a pop window to show "successfully saved"
+ /**
+ * Saves the puzzle using the current file name and shows a message dialog to
+ * confirm that the save operation was successful. If the puzzle or exporter is null, or if
+ * an error occurs during export, the method will catch the exception and print the stack trace.
+ */
private void saveProofChange() {
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
if (puzzle == null) {
@@ -688,13 +771,22 @@ private void saveProofChange() {
}
}
- // ask to edu.rpi.legup.save current proof
+ /**
+ * Displays a confirmation dialog with a specified message. Returns {@code true} if the user
+ * selects "No" or cancels the action, and {@code false} if the user selects "Yes".
+ *
+ * @param instr the message to display in the confirmation dialog
+ * @return {@code true} if the user chooses not to quit, {@code false} otherwise
+ */
public boolean noquit(String instr) {
int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION);
return n != JOptionPane.YES_OPTION;
}
- /** Sets the main content for the edu.rpi.legup.user interface */
+ /**
+ * Configures the layout and components for the main user interface. This includes setting up
+ * panels, split panes, and borders, and adding them to the main content pane.
+ */
protected void setupContent() {
// JPanel consoleBox = new JPanel(new BorderLayout());
JPanel treeBox = new JPanel(new BorderLayout());
@@ -727,110 +819,191 @@ protected void setupContent() {
ruleBox.add(boardPanel);
treeBox.add(ruleBox);
this.add(treeBox);
- // consoleBox.add(treeBox);
- //
- // getContentPane().add(consoleBox);
-
- // JPopupPanel popupPanel = new JPopupPanel();
- // setGlassPane(popupPanel);
- // popupPanel.setVisible(true);
mainPanel.setDividerLocation(mainPanel.getMaximumDividerLocation() + 100);
- // frame.pack();
+
revalidate();
}
- private void setupToolBar() {
- setToolBarButtons(new JButton[ToolbarName.values().length]);
- for (int i = 0; i < ToolbarName.values().length; i++) {
- String toolBarName = ToolbarName.values()[i].toString();
- URL resourceLocation =
- ClassLoader.getSystemClassLoader()
- .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png");
-
- // Scale the image icons down to make the buttons smaller
- ImageIcon imageIcon = new ImageIcon(resourceLocation);
- Image image = imageIcon.getImage();
- imageIcon =
- new ImageIcon(
- image.getScaledInstance(
- this.TOOLBAR_ICON_SCALE,
- this.TOOLBAR_ICON_SCALE,
- Image.SCALE_SMOOTH));
-
- JButton button = new JButton(toolBarName, imageIcon);
- button.setFocusPainted(false);
- getToolBarButtons()[i] = button;
- }
-
- toolBar = new JToolBar();
- toolBar.setFloatable(false);
- toolBar.setRollover(true);
+ /**
+ * Initializes the first toolbar, configures its appearance, and adds an 'Open' button
+ * with an associated icon. An action listener is attached to the button to trigger the loading of
+ * a puzzle when clicked.
+ */
+ private void setupToolBar1() {
+ toolBar1 = new JToolBar();
+ toolBar1.setFloatable(false);
+ toolBar1.setRollover(true);
+ setToolBar2Buttons(new JButton[1]);
+
+ URL open_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Open.png");
+
+ // Scale the image icons down to make the buttons smaller
+ ImageIcon OpenImageIcon = new ImageIcon(open_url);
+ Image OpenImage = OpenImageIcon.getImage();
+ OpenImageIcon =
+ new ImageIcon(
+ OpenImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton open = new JButton("Open", OpenImageIcon);
+ open.setFocusPainted(false);
+
+ open.addActionListener((ActionEvent) -> loadPuzzle());
+
+ getToolBar2Buttons()[0] = open;
+ toolBar1.add(getToolBar2Buttons()[0]);
+
+ this.add(toolBar1, BorderLayout.NORTH);
+ }
- for (int i = 0; i < getToolBarButtons().length; i++) {
- for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) {
- if (i == TOOLBAR_SEPARATOR_BEFORE[s]) {
- toolBar.addSeparator();
- }
- }
- String toolBarName = ToolbarName.values()[i].toString();
+ /**
+ * Initializes the second toolbar, configures its appearance, and adds four buttons each
+ * with associated icons. Action listeners are attached to each button to trigger their respective
+ * actions when clicked:
+ *
+ * - 'Directions' button triggers the `directionsToolButton` method.
+ * - 'Undo' button triggers the undo action in the puzzle's history.
+ * - 'Redo' button triggers the redo action in the puzzle's history.
+ * - 'Check' button triggers the `checkProof` method.
+ *
+ */
+ private void setupToolBar2() {
+ toolBar2 = new JToolBar();
+ toolBar2.setFloatable(false);
+ toolBar2.setRollover(true);
+ setToolBar2Buttons(new JButton[4]);
+
+ URL directions_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Directions.png");
+
+ ImageIcon DirectionsImageIcon = new ImageIcon(directions_url);
+ Image DirectionsImage = DirectionsImageIcon.getImage();
+ DirectionsImageIcon =
+ new ImageIcon(
+ DirectionsImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton directions = new JButton("Directions", DirectionsImageIcon);
+ directions.setFocusPainted(false);
+ directions.addActionListener((ActionEvent) -> directionsToolButton());
+
+ getToolBar2Buttons()[0] = directions;
+ toolBar2.add(getToolBar2Buttons()[0]);
+
+ URL undo_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Undo.png");
+
+ ImageIcon UndoImageIcon = new ImageIcon(undo_url);
+ Image UndoImage = UndoImageIcon.getImage();
+ UndoImageIcon =
+ new ImageIcon(
+ UndoImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton undo = new JButton("Undo", UndoImageIcon);
+ undo.setFocusPainted(false);
+ undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo());
- toolBar.add(getToolBarButtons()[i]);
- getToolBarButtons()[i].setToolTipText(toolBarName);
+ getToolBar2Buttons()[1] = undo;
+ toolBar2.add(getToolBar2Buttons()[1]);
+
+ URL redo_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Redo.png");
+
+ ImageIcon RedoImageIcon = new ImageIcon(redo_url);
+ Image RedoImage = RedoImageIcon.getImage();
+ RedoImageIcon =
+ new ImageIcon(
+ RedoImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton redo = new JButton("Redo", RedoImageIcon);
+ redo.setFocusPainted(false);
+ redo.addActionListener((ActionEvent) -> {
+ GameBoardFacade.getInstance().getHistory().redo();
+ });
+
+ getToolBar2Buttons()[2] = redo;
+ toolBar2.add(getToolBar2Buttons()[2]);
+
+ URL check_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Check.png");
+
+ ImageIcon CheckImageIcon = new ImageIcon(check_url);
+ Image CheckImage = CheckImageIcon.getImage();
+ CheckImageIcon =
+ new ImageIcon(
+ CheckImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton check = new JButton("Check", CheckImageIcon);
+ check.setFocusPainted(false);
+ check.addActionListener((ActionEvent) -> checkProof());
+
+ getToolBar2Buttons()[3] = check;
+ toolBar2.add(getToolBar2Buttons()[3]);
+
+
+ this.add(toolBar2, BorderLayout.NORTH);
+ }
- getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM);
- getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER);
- }
+ /**
+ * Sets the toolbar1 buttons
+ *
+ * @param toolBar1Buttons toolbar buttons
+ */
+ public void setToolBar1Buttons(JButton[] toolBar1Buttons) {
+ this.toolBar1Buttons = toolBar1Buttons;
+ }
- // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent
- // e) ->
- // promptPuzzle());
- // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) ->
- // saveProof());
- // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) ->
- // GameBoardFacade.getInstance().getHistory().undo());
- // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) ->
- // GameBoardFacade.getInstance().getHistory().redo());
- toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {});
- toolBarButtons[ToolbarName.CHECK.ordinal()].addActionListener(
- (ActionEvent e) -> checkProof());
- toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {});
- toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {});
-
- toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener(
- (ActionEvent e) -> checkProofAll());
-
- // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(true);
-
- this.add(toolBar, BorderLayout.NORTH);
+ /**
+ * Sets the toolbar2 buttons
+ *
+ * @param toolBar2Buttons toolbar buttons
+ */
+ public void setToolBar2Buttons(JButton[] toolBar2Buttons) {
+ this.toolBar2Buttons = toolBar2Buttons;
}
/**
- * Sets the toolbar buttons
+ * Gets the toolbar1 buttons
*
- * @param toolBarButtons toolbar buttons
+ * @return toolbar1 buttons
*/
- public void setToolBarButtons(JButton[] toolBarButtons) {
- this.toolBarButtons = toolBarButtons;
+ public JButton[] getToolBar1Buttons() {
+ return toolBar1Buttons;
}
/**
- * Gets the toolbar buttons
+ * Gets the toolbar2 buttons
*
- * @return toolbar buttons
+ * @return toolbar2 buttons
*/
- public JButton[] getToolBarButtons() {
- return toolBarButtons;
+ public JButton[] getToolBar2Buttons() {
+ return toolBar2Buttons;
}
- /** Checks the proof for correctness */
+ /**
+ * Uses the {@link GameBoardFacade} to obtain the current puzzle and board. If the puzzle is complete,
+ * it notifies the user of a correct proof. If not, it alerts the user that the board is not solved.
+ */
private void checkProof() {
GameBoardFacade facade = GameBoardFacade.getInstance();
Tree tree = GameBoardFacade.getInstance().getTree();
@@ -857,14 +1030,58 @@ private void checkProof() {
}
}
+ /**
+ * Retrieves the puzzle name from the `GameBoardFacade` and opens a corresponding rules page in the default web browser.
+ *
+ * @throws IOException if an error occurs while trying to open the web page
+ */
+ private void directionsToolButton() {
+ String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName();
+ //System.out.println(puzzleName);
+ try {
+ if (puzzleName.equals("Fillapix")) {
+ java.awt.Desktop.getDesktop()
+ .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Fill-a-pix-rules"));
+ }
+ else if (puzzleName.equals("LightUp")) {
+ java.awt.Desktop.getDesktop()
+ .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Light-up-rules"));
+ }
+ else if (puzzleName.equals("TreeTent")) {
+ java.awt.Desktop.getDesktop()
+ .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Tree-tent-rules"));
+ }
+ else if (puzzleName.equals("ShortTruthTables")) {
+ java.awt.Desktop.getDesktop()
+ .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Short-truth-table-rules"));
+ }
+ else {
+ java.awt.Desktop.getDesktop()
+ .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/" + puzzleName + "-rules"));
+ }
+ } catch (IOException e) {
+ LOGGER.error("Can't open web page");
+ }
+ }
+
+ /**
+ * Repaints the board view and tree panel
+ */
private void repaintAll() {
boardView.repaint();
treePanel.repaint();
}
+ /**
+ * Initializes the dynamic board view, updates the tree panel, and sets rules and search panels
+ * based on the provided puzzle. It also updates toolbars and reloads the GUI.
+ *
+ * @param puzzle the puzzle to be displayed
+ */
public void setPuzzleView(Puzzle puzzle) {
this.boardView = puzzle.getBoardView();
+
dynamicBoardView = new DynamicView(boardView, DynamicViewType.BOARD);
this.topHalfPanel.setRightComponent(dynamicBoardView);
this.topHalfPanel.setVisible(true);
@@ -885,16 +1102,20 @@ public void setPuzzleView(Puzzle puzzle) {
ruleFrame.getContradictionPanel().setRules(puzzle.getContradictionRules());
ruleFrame.getSearchPanel().setSearchBar(puzzle);
- toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true);
- // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true);
-
+ toolBar1.setVisible(false);
+ setupToolBar2();
reloadGui();
}
+ /**
+ * Calls {@code repaintTree()} to refresh the tree view.
+ */
public void reloadGui() {
repaintTree();
}
-
+ /**
+ * Updates the tree view displayed in the tree panel to reflect the current state of the tree.
+ */
public void repaintTree() {
treePanel.repaintTreeView(GameBoardFacade.getInstance().getTree());
}
@@ -949,6 +1170,15 @@ private boolean basicCheckProof(int[][] origCells) {
return false;
}
+ /**
+ * Traverses a given directory, grades the proofs found in the directory, and writes the results
+ * to the specified CSV writer.
+ *
+ * @param folder the folder to traverse
+ * @param writer the CSV writer
+ * @param path the current path in the directory traversal
+ * @throws IOException if an error occurs while writing to the CSV file
+ */
private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException {
// Recursively traverse directory
GameBoardFacade facade = GameBoardFacade.getInstance();
@@ -1003,20 +1233,36 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws
}
}
+ /**
+ * Returns the current board view.
+ *
+ * @return the current {@link BoardView}
+ */
public BoardView getBoardView() {
return boardView;
}
+
+ /**
+ * Returns the current dynamic board view.
+ *
+ * @return the current {@link DynamicView}
+ */
public DynamicView getDynamicBoardView() {
return dynamicBoardView;
}
+ /**
+ * Returns the current tree panel.
+ *
+ * @return the current {@link TreePanel}
+ */
public TreePanel getTreePanel() {
return treePanel;
}
/**
- * Called when a action is pushed onto the edu.rpi.legup.history stack
+ * Called when an action is pushed onto the edu.rpi.legup.history stack
*
* @param command action to push onto the stack
*/
@@ -1024,22 +1270,19 @@ public TreePanel getTreePanel() {
public void onPushChange(ICommand command) {
LOGGER.info("Pushing " + command.getClass().getSimpleName() + " to stack.");
undo.setEnabled(true);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(true);
redo.setEnabled(false);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false);
String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName();
File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName());
frame.setTitle(puzzleName + " - " + puzzleFile.getName() + " *");
}
- /** Called when the history is cleared */
+ /**
+ * Updates the state of the undo and redo buttons to reflect that there are no actions
+ * available to undo or redo. It disables both buttons when the history is cleared.
+ */
@Override
public void onClearHistory() {
- // undo.setEnabled(false);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false);
- // redo.setEnabled(false);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false);
}
/**
@@ -1051,9 +1294,7 @@ public void onClearHistory() {
@Override
public void onRedo(boolean isBottom, boolean isTop) {
undo.setEnabled(!isBottom);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom);
redo.setEnabled(!isTop);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop);
if (isBottom) {
String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName();
File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName());
@@ -1074,9 +1315,7 @@ public void onRedo(boolean isBottom, boolean isTop) {
@Override
public void onUndo(boolean isBottom, boolean isTop) {
undo.setEnabled(!isBottom);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom);
redo.setEnabled(!isTop);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop);
String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName();
File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName());
if (isBottom) {
@@ -1120,6 +1359,10 @@ public void showStatus(String status, boolean error, int timer) {
// TODO: implement
}
+
+ /**
+ * Zooms the tree view to fit within the available screen space
+ */
protected void fitTreeViewToScreen() {
this.treePanel.getTreeView().zoomFit();
}
diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java
index f50c8d6fc..2f3c16eac 100644
--- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java
@@ -10,9 +10,14 @@
import edu.rpi.legup.history.IHistoryListener;
import edu.rpi.legup.model.Puzzle;
import edu.rpi.legup.model.PuzzleExporter;
+import edu.rpi.legup.model.tree.Tree;
+import edu.rpi.legup.model.tree.TreeNode;
+import edu.rpi.legup.model.tree.TreeTransition;
import edu.rpi.legup.save.ExportFileException;
import edu.rpi.legup.save.InvalidFileFormatException;
+import edu.rpi.legup.ui.HomePanel;
import edu.rpi.legup.ui.boardview.BoardView;
+import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection;
import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementFrame;
import java.awt.*;
import java.awt.event.ActionEvent;
@@ -22,24 +27,32 @@
import java.io.IOException;
import java.net.URI;
import java.net.URL;
+import java.util.List;
import java.util.Objects;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+/**
+ * Represents the panel used for puzzle editor in the LEGUP.
+ * This panel includes a variety of UI components such as toolbars, menus, and split panes.
+ * It handles puzzle file operations, including creating and editing puzzles.
+ */
public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener {
private static final Logger LOGGER = LogManager.getLogger(PuzzleEditorPanel.class.getName());
private JMenu[] menus;
private JMenuItem helpLegup, aboutLegup;
private JMenuBar menuBar;
- private JToolBar toolBar;
+ private JToolBar toolBar1;
+ private JToolBar toolBar2;
private JFileChooser folderBrowser;
private JFrame frame;
private JButton[] buttons;
JSplitPane splitPanel;
- private JButton[] toolBarButtons;
+ private JButton[] toolBar1Buttons;
+ private JButton[] toolBar2Buttons;
private JPanel elementPanel;
private DynamicView dynamicBoardView;
private BoardView boardView;
@@ -51,8 +64,19 @@ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener {
private JPanel treePanel;
private LegupUI legupUI;
private EditorElementController editorElementController;
- static final int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8};
-
+ private CreatePuzzleDialog cpd;
+ private HomePanel hp;
+ private boolean existingPuzzle;
+ private String fileName;
+ private File puzzleFile;
+
+ /**
+ * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI instance
+ *
+ * @param fileDialog the file dialog used for file operations
+ * @param frame the main application frame
+ * @param legupUI the Legup UI instance
+ */
public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) {
this.fileDialog = fileDialog;
this.frame = frame;
@@ -61,6 +85,10 @@ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) {
setPreferredSize(new Dimension(800, 700));
}
+ /**
+ * Sets up the content of the panel, including the layout and UI components.
+ * Initializes and configures the {@code DynamicView} and {@code ElementFrame}, and adds them to the panel.
+ */
protected void setupContent() {
JSplitPane splitPanel;
JPanel elementBox = new JPanel(new BorderLayout());
@@ -92,6 +120,11 @@ protected void setupContent() {
revalidate();
}
+ /**
+ * Configures the menu bar with menus and menu items for the application.
+ * Adds actions for opening, creating, and exiting puzzles.
+ * Also sets up help and about menu items.
+ */
public void setMenuBar() {
String os = LegupUI.getOS();
menuBar = new JMenuBar();
@@ -103,28 +136,33 @@ public void setMenuBar() {
menus[0] = new JMenu("File");
// file>new
- JMenuItem newPuzzle = new JMenuItem("New");
- newPuzzle.addActionListener((ActionEvent) -> loadPuzzle());
+ JMenuItem openPuzzle = new JMenuItem("Open");
+ openPuzzle.addActionListener((ActionEvent) -> loadPuzzle());
if (os.equals("mac")) {
- newPuzzle.setAccelerator(
+ openPuzzle.setAccelerator(
KeyStroke.getKeyStroke(
- 'N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ 'O', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
} else {
- newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_DOWN_MASK));
+ openPuzzle.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK));
}
- // file>save
- JMenuItem savePuzzle = new JMenuItem("Save As");
- savePuzzle.addActionListener((ActionEvent) -> savePuzzle());
- JMenuItem directSavePuzzle = new JMenuItem("Direct Save Proof ");
- directSavePuzzle.addActionListener((ActionEvent) -> direct_save());
+ // file>create
+ JMenuItem createPuzzle = new JMenuItem("Create");
+ createPuzzle.addActionListener((ActionEvent) -> {
+ hp = new HomePanel(this.frame, this.legupUI);
+ cpd = new CreatePuzzleDialog(this.frame, hp);
+ cpd.setLocationRelativeTo(null);
+ cpd.setVisible(true);
+ existingPuzzle = false;
+ });
if (os.equals("mac")) {
- newPuzzle.setAccelerator(
+ createPuzzle.setAccelerator(
KeyStroke.getKeyStroke(
- 'D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
} else {
- newPuzzle.setAccelerator(KeyStroke.getKeyStroke('D', InputEvent.CTRL_DOWN_MASK));
+ createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK));
}
+
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener((ActionEvent) -> exitEditor());
if (os.equals("mac")) {
@@ -134,9 +172,9 @@ public void setMenuBar() {
} else {
exit.setAccelerator(KeyStroke.getKeyStroke('Q', InputEvent.CTRL_DOWN_MASK));
}
- menus[0].add(newPuzzle);
- menus[0].add(savePuzzle);
- menus[0].add(directSavePuzzle);
+ menus[0].add(openPuzzle);
+ menus[0].add(createPuzzle);
+ //menus[0].add(directSavePuzzle);
menus[0].add(exit);
// EDIT
@@ -147,7 +185,8 @@ public void setMenuBar() {
redo = new JMenuItem("Redo");
fitBoardToScreen = new JMenuItem("Fit Board to Screen");
- menus[1].add(undo);
+ // TODO: Undo operation currently does not get updated correctly in history
+ //menus[1].add(undo);
undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo());
if (os.equals("mac")) {
undo.setAccelerator(
@@ -157,8 +196,8 @@ public void setMenuBar() {
undo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.CTRL_DOWN_MASK));
}
- menus[1].add(redo);
-
+ // TODO: Redo operation currently does not get updated correctly in history
+ //menus[1].add(redo);
// Created action to support two keybinds (CTRL-SHIFT-Z, CTRL-Y)
Action redoAction =
new AbstractAction() {
@@ -232,6 +271,12 @@ public void actionPerformed(ActionEvent e) {
frame.setJMenuBar(menuBar);
}
+ /**
+ * Exits the puzzle editor and resets the application state to its initial condition.
+ * This method clears the current puzzle from the {@code GameBoardFacade},
+ * resets the display to the initial panel, and nullifies references to the
+ * tree panel and board view.
+ */
public void exitEditor() {
// Wipes the puzzle entirely as if LEGUP just started
GameBoardFacade.getInstance().clearPuzzle();
@@ -240,118 +285,188 @@ public void exitEditor() {
boardView = null;
}
+ /**
+ * Makes the panel visible by setting up the toolbar, content, and menu bar.
+ * This method is called to refresh the panel's user interface.
+ */
@Override
public void makeVisible() {
this.removeAll();
-
- setupToolBar();
+ setupToolBar1();
setupContent();
setMenuBar();
}
- private void setupToolBar() {
- setToolBarButtons(new JButton[ToolbarName.values().length + 1]);
- int lastone = 0;
- for (int i = 0; i < ToolbarName.values().length - 1; i++) {
- String toolBarName = ToolbarName.values()[i].toString();
- URL resourceLocation =
- ClassLoader.getSystemClassLoader()
- .getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png");
-
- // Scale the image icons down to make the buttons smaller
- ImageIcon imageIcon = new ImageIcon(resourceLocation);
- Image image = imageIcon.getImage();
- imageIcon =
- new ImageIcon(
- image.getScaledInstance(
- this.TOOLBAR_ICON_SCALE,
- this.TOOLBAR_ICON_SCALE,
- Image.SCALE_SMOOTH));
-
- JButton button = new JButton(toolBarName, imageIcon);
- button.setFocusPainted(false);
- getToolBarButtons()[i] = button;
- lastone = i;
- }
+ /**
+ * Sets up the first toolbar with buttons for opening and creating puzzles.
+ * This method initializes the toolbar buttons with their icons and actions.
+ */
+ private void setupToolBar1() {
+ setToolBar1Buttons(new JButton[2]);
- URL check_and_save =
+ URL open_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Open.png");
+ ImageIcon OpenImageIcon = new ImageIcon(open_url);
+ Image OpenImage = OpenImageIcon.getImage();
+ OpenImageIcon =
+ new ImageIcon(
+ OpenImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton open = new JButton("Open", OpenImageIcon);
+ open.setFocusPainted(false);
+ open.addActionListener((ActionEvent) -> loadPuzzle());
+
+ getToolBar1Buttons()[0] = open;
+
+ toolBar1 = new JToolBar();
+ toolBar1.setFloatable(false);
+ toolBar1.setRollover(true);
+ toolBar1.add(getToolBar1Buttons()[0]);
+
+ URL create_url =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Open Puzzle.png");
+ ImageIcon CreateImageIcon = new ImageIcon(create_url);
+ Image CreateImage = CreateImageIcon.getImage();
+ CreateImageIcon =
+ new ImageIcon(
+ CreateImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton create = new JButton("Create", CreateImageIcon);
+ create.setFocusPainted(false);
+ create.addActionListener((ActionEvent) -> {
+ hp = new HomePanel(this.frame, this.legupUI);
+ cpd = new CreatePuzzleDialog(this.frame, hp);
+ cpd.setLocationRelativeTo(null);
+ cpd.setVisible(true);
+ existingPuzzle = false;
+ });
+ getToolBar1Buttons()[1] = create;
+
+ toolBar1.setFloatable(false);
+ toolBar1.setRollover(true);
+ toolBar1.add(getToolBar1Buttons()[1]);
+
+ this.add(toolBar1, BorderLayout.NORTH);
+ }
+
+ /**
+ * Sets up the second toolbar with buttons for resetting, saving, and saving & solving puzzles.
+ * This method initializes the toolbar buttons with their icons and actions.
+ */
+ private void setupToolBar2() {
+ toolBar2 = new JToolBar();
+ toolBar2.setFloatable(false);
+ toolBar2.setRollover(true);
+ setToolBar2Buttons(new JButton[3]);
+
+ URL reset =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Reset.png");
+ ImageIcon ResetImageIcon = new ImageIcon(reset);
+ Image ResetImage = ResetImageIcon.getImage();
+ ResetImageIcon =
+ new ImageIcon(
+ ResetImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton resetButton = new JButton("Reset", ResetImageIcon);
+ resetButton.setFocusPainted(false);
+
+ resetButton.addActionListener(
+ a -> {
+ if (existingPuzzle) {
+ legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile);
+ }
+ else {
+ if (cpd.getGame().equals("ShortTruthTable")) {
+ GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea());
+ }
+ else {
+ GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns()));
+ }
+ }
+ });
+
+ getToolBar2Buttons()[0] = resetButton;
+ toolBar2.add(getToolBar2Buttons()[0]);
+
+ URL save_as =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Save.png");
+ ImageIcon SaveAsImageIcon = new ImageIcon(save_as);
+ Image SaveAsImage = SaveAsImageIcon.getImage();
+ SaveAsImageIcon =
+ new ImageIcon(
+ SaveAsImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton saveas = new JButton("Save As", SaveAsImageIcon);
+ saveas.setFocusPainted(false);
+ saveas.addActionListener((ActionEvent) -> savePuzzle());
+
+ getToolBar2Buttons()[1] = saveas;
+ toolBar2.add(getToolBar2Buttons()[1]);
+
+ URL save_and_solve =
ClassLoader.getSystemClassLoader()
.getResource("edu/rpi/legup/images/Legup/Check.png");
- ImageIcon imageIcon = new ImageIcon(check_and_save);
- Image image = imageIcon.getImage();
- imageIcon =
+ ImageIcon SaveSolveImageIcon = new ImageIcon(save_and_solve);
+ Image SaveSolveImage = SaveSolveImageIcon.getImage();
+ SaveSolveImageIcon =
new ImageIcon(
- image.getScaledInstance(
+ SaveSolveImage.getScaledInstance(
this.TOOLBAR_ICON_SCALE,
this.TOOLBAR_ICON_SCALE,
Image.SCALE_SMOOTH));
- JButton checkandsave = new JButton("check and Save", imageIcon);
- checkandsave.setFocusPainted(false);
- checkandsave.addActionListener(
+ JButton saveandsolve = new JButton("Save & Solve", SaveSolveImageIcon);
+ saveandsolve.setFocusPainted(false);
+ saveandsolve.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- // savePuzzle();
- String filename = savePuzzle();
- File puzzlename = new File(filename);
- System.out.println(filename);
-
- GameBoardFacade.getInstance().getLegupUI().displayPanel(1);
- GameBoardFacade.getInstance()
- .getLegupUI()
- .getProofEditor()
- .loadPuzzle(filename, new File(filename));
- String puzzleName =
- GameBoardFacade.getInstance().getPuzzleModule().getName();
- frame.setTitle(puzzleName + " - " + puzzlename.getName());
+ if (GameBoardFacade.getInstance().getPuzzleModule() != null) {
+ String filename = savePuzzle();
+ File puzzlename = new File(filename);
+ System.out.println(filename);
+
+ GameBoardFacade.getInstance().getLegupUI().displayPanel(1);
+ GameBoardFacade.getInstance()
+ .getLegupUI()
+ .getProofEditor()
+ .loadPuzzle(filename, new File(filename));
+ String puzzleName =
+ GameBoardFacade.getInstance().getPuzzleModule().getName();
+ frame.setTitle(puzzleName + " - " + puzzlename.getName());
+ }
}
});
- getToolBarButtons()[lastone + 1] = checkandsave;
- System.out.println("it is create new file");
+ getToolBar2Buttons()[2] = saveandsolve;
+ toolBar2.add(getToolBar2Buttons()[2]);
- toolBar = new JToolBar();
- toolBar.setFloatable(false);
- toolBar.setRollover(true);
-
- for (int i = 0; i < getToolBarButtons().length - 1; i++) {
- for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) {
- if (i == TOOLBAR_SEPARATOR_BEFORE[s]) {
- toolBar.addSeparator();
- }
- }
- String toolBarName = ToolbarName.values()[i].toString();
-
- toolBar.add(getToolBarButtons()[i]);
- getToolBarButtons()[i].setToolTipText(toolBarName);
-
- getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM);
- getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER);
- }
-
- // toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent
- // e) ->
- // promptPuzzle());
- // toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) ->
- // saveProof());
- // toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) ->
- // GameBoardFacade.getInstance().getHistory().undo());
- // toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) ->
- // GameBoardFacade.getInstance().getHistory().redo());
- toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> {});
- toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> {});
- toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> {});
-
- // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false);
- // toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false);
- // toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false);
- toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false);
-
- this.add(toolBar, BorderLayout.NORTH);
+ this.add(toolBar2, BorderLayout.NORTH);
}
+ /**
+ * Initializes a puzzle based on the provided game name, rows, and columns.
+ *
+ * @param game the name of the game or puzzle to load
+ * @param rows the number of rows in the puzzle
+ * @param columns the number of columns in the puzzle
+ * @throws IllegalArgumentException if the provided arguments are invalid
+ */
public void loadPuzzleFromHome(String game, int rows, int columns)
throws IllegalArgumentException {
GameBoardFacade facade = GameBoardFacade.getInstance();
@@ -365,6 +480,13 @@ public void loadPuzzleFromHome(String game, int rows, int columns)
}
}
+ /**
+ * Initializes a puzzle based on the provided game name and an array of statements.
+ *
+ * @param game the name of the game or puzzle to load
+ * @param statements an array of statements to initialize the puzzle
+ * @throws IllegalArgumentException if the provided arguments are invalid
+ */
public void loadPuzzleFromHome(String game, String[] statements) {
GameBoardFacade facade = GameBoardFacade.getInstance();
try {
@@ -377,11 +499,17 @@ public void loadPuzzleFromHome(String game, String[] statements) {
}
}
- // File opener
+ /**
+ * Prompts the user to select a puzzle file to open.
+ * Opens a file chooser dialog and returns the selected file's name and file object.
+ * If a puzzle is currently loaded, prompts the user to confirm if they want to open a new puzzle.
+ *
+ * @return an array containing the selected file name and file object, or null if the operation was canceled
+ */
public Object[] promptPuzzle() {
GameBoardFacade facade = GameBoardFacade.getInstance();
if (facade.getBoard() != null) {
- if (noQuit("Opening a new puzzle?")) {
+ if (noQuit("Open an existing puzzle?")) {
return new Object[0];
}
}
@@ -405,7 +533,6 @@ public Object[] promptPuzzle() {
fileBrowser.setAcceptAllFileFilterUsed(false);
File puzzlePath = fileBrowser.getSelectedFile();
- System.out.println(puzzlePath.getAbsolutePath());
if (puzzlePath != null) {
fileName = puzzlePath.getAbsolutePath();
@@ -420,6 +547,11 @@ public Object[] promptPuzzle() {
return new Object[] {fileName, puzzleFile};
}
+ /**
+ * Loads a puzzle by prompting the user to select a puzzle file.
+ * If the user cancels the operation, no action is taken. If a puzzle file is selected,
+ * it will be loaded using the file name and file object.
+ */
public void loadPuzzle() {
Object[] items = promptPuzzle();
// Return if items == null (cancel)
@@ -431,6 +563,14 @@ public void loadPuzzle() {
loadPuzzle(fileName, puzzleFile);
}
+ /**
+ * Loads a puzzle from the specified file.
+ * If the puzzle file is valid and exists, it loads the puzzle and updates the UI.
+ * If the file format is invalid, an error message is displayed.
+ *
+ * @param fileName the name of the puzzle file
+ * @param puzzleFile the file object representing the puzzle file
+ */
public void loadPuzzle(String fileName, File puzzleFile) {
if (puzzleFile != null && puzzleFile.exists()) {
try {
@@ -438,6 +578,9 @@ public void loadPuzzle(String fileName, File puzzleFile) {
GameBoardFacade.getInstance().loadPuzzleEditor(fileName);
String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName();
frame.setTitle(puzzleName + " - " + puzzleFile.getName());
+ existingPuzzle = true;
+ this.fileName = fileName;
+ this.puzzleFile = puzzleFile;
} catch (InvalidFileFormatException e) {
legupUI.displayPanel(0);
LOGGER.error(e.getMessage());
@@ -451,42 +594,103 @@ public void loadPuzzle(String fileName, File puzzleFile) {
}
}
+ /**
+ * Displays a confirmation dialog with the given instruction message.
+ * The method returns true if the user selected "No" or cancelled the dialog,
+ * and false if the user selected "Yes".
+ *
+ * @param instr the instruction message to display in the confirmation dialog
+ * @return true if the user selected "No" or canceled; false if the user selected "Yes"
+ */
public boolean noQuit(String instr) {
int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION);
return n != JOptionPane.YES_OPTION;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onPushChange(ICommand command) {}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onUndo(boolean isBottom, boolean isTop) {}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onRedo(boolean isBottom, boolean isTop) {}
+ /**
+ * {@inheritDoc}
+ */
@Override
public void onClearHistory() {
- // undo.setEnabled(false);
- // redo.setEnabled(false);
}
+
+ /**
+ * Returns the current board view
+ *
+ * @return the board view
+ */
public BoardView getBoardView() {
return boardView;
}
- public JButton[] getToolBarButtons() {
- return toolBarButtons;
+ /**
+ * Returns the array of buttons for the first toolbar
+ *
+ * @return the array of toolbar1 buttons
+ */
+ public JButton[] getToolBar1Buttons() {
+ return toolBar1Buttons;
+ }
+
+ /**
+ * Sets the array of buttons for the first toolbar
+ *
+ * @param toolBar1Buttons the array of toolbar1 buttons
+ */
+ public void setToolBar1Buttons(JButton[] toolBar1Buttons) {
+ this.toolBar1Buttons = toolBar1Buttons;
}
- public void setToolBarButtons(JButton[] toolBarButtons) {
- this.toolBarButtons = toolBarButtons;
+ /**
+ * Returns the array of buttons for the second toolbar
+ *
+ * @return the array of toolbar2 buttons
+ */
+ public JButton[] getToolBar2Buttons() {
+ return toolBar2Buttons;
}
+ /**
+ * Sets the array of buttons for the second toolbar
+ *
+ * @param toolBar2Buttons the array of toolbar2 buttons
+ */
+ public void setToolBar2Buttons(JButton[] toolBar2Buttons) {
+ this.toolBar2Buttons = toolBar2Buttons;
+ }
+
+ /**
+ * Repaints the current board view
+ */
private void repaintAll() {
boardView.repaint();
}
+ /**
+ * Sets the puzzle view based on the provided puzzle object.
+ * Updates the UI components to display the new puzzle.
+ *
+ * @param puzzle the puzzle object to display
+ */
public void setPuzzleView(Puzzle puzzle) {
this.boardView = puzzle.getBoardView();
editorElementController.setElementController(boardView.getElementController());
@@ -502,13 +706,11 @@ public void setPuzzleView(Puzzle puzzle) {
dynamicBoardView.setBorder(titleBoard);
puzzle.addBoardListener(puzzle.getBoardView());
- System.out.println("Setting elements");
if (this.elementFrame != null) {
elementFrame.setElements(puzzle);
}
-
- toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true);
- // toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true);
+ toolBar1.setVisible(false);
+ setupToolBar2();
}
/** Saves a puzzle */
@@ -531,6 +733,13 @@ private void direct_save() {
}
}
+ /**
+ * Saves the current puzzle to a user-selected directory.
+ * Prompts the user to select a directory and saves the puzzle to that directory.
+ * Returns the path where the puzzle was saved.
+ *
+ * @return the path where the puzzle was saved, or an empty string if the save operation was canceled
+ */
private String savePuzzle() {
Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule();
if (puzzle == null) {
@@ -567,7 +776,7 @@ private String savePuzzle() {
folderBrowser.setAcceptAllFileFilterUsed(false);
String path = folderBrowser.getSelectedFile().getAbsolutePath();
-
+ preferences.setSavedPath(path);
if (path != null) {
try {
PuzzleExporter exporter = puzzle.getExporter();
@@ -582,6 +791,11 @@ private String savePuzzle() {
return path;
}
+ /**
+ * Returns the current dynamic board view
+ *
+ * @return the dynamic board view
+ */
public DynamicView getDynamicBoardView() {
return dynamicBoardView;
}
diff --git a/src/main/java/edu/rpi/legup/ui/ScrollView.java b/src/main/java/edu/rpi/legup/ui/ScrollView.java
index 0bf8335a2..18aff4d1c 100644
--- a/src/main/java/edu/rpi/legup/ui/ScrollView.java
+++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java
@@ -6,6 +6,10 @@
import java.util.logging.Logger;
import javax.swing.*;
+/**
+ * ScrollView extends {@link JScrollPane} to provide a customizable view with zoom and scroll capabilities.
+ * It uses a {@link ZoomablePane} as the canvas and allows for zooming and scrolling with respect to the canvas content.
+ */
public class ScrollView extends JScrollPane {
private static final Logger LOGGER = Logger.getLogger(ScrollView.class.getName());
@@ -165,6 +169,11 @@ public void zoom(int n, Point point) {
revalidate();
}
+ /**
+ * Adjusts the zoom level to the given scale and centers the viewport on the current center point
+ *
+ * @param newScale the new scale to set
+ */
public void zoomTo(double newScale) {
// check zoom bounds
if (newScale < minScale) {
@@ -282,6 +291,11 @@ public void setSize(Dimension size) {
updateSize();
}
+ /**
+ * Gets the canvas for this {@code ScrollView}
+ *
+ * @return the ZoomablePane instance used as the canvas
+ */
public ZoomablePane getCanvas() {
return canvas;
}
diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java
index ba02ebd2e..53936a141 100644
--- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java
+++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java
@@ -1,11 +1,12 @@
package edu.rpi.legup.ui;
+/**
+ * This enum defines constants for toolbar names used in the user interface.
+ * Each represents a specific toolbar action.
+ */
public enum ToolbarName {
- HINT,
- CHECK,
- SUBMIT,
DIRECTIONS,
- CHECK_ALL;
+ CHECK;
/**
* Gets the String representation of the ToolbarName enum
diff --git a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java
index aa5b65c4e..34e828250 100644
--- a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java
+++ b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java
@@ -10,6 +10,10 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+/**
+ * The {@code ZoomWidget} displays a zoom icon that, when clicked, shows a popup slider to adjust
+ * the zoom level of the associated {@code ScrollView}.
+ */
public class ZoomWidget extends JLabel {
private ScrollView parent;
private PopupSlider palette = new PopupSlider();
@@ -32,12 +36,17 @@ public ZoomWidget(ScrollView parent) {
addMouseListener(open);
}
- /** */
+ /**
+ * A {@code JPopupMenu} subclass that contains a vertical slider for adjusting zoom level.
+ */
private class PopupSlider extends JPopupMenu implements ChangeListener {
private static final long serialVersionUID = 8225019381200459814L;
private JSlider slider;
+ /**
+ * Constructs a {@code PopupSlider} with a vertical slider
+ */
public PopupSlider() {
slider = new JSlider(SwingConstants.VERTICAL, 0, 400, 200);
slider.setMajorTickSpacing(25);
@@ -47,6 +56,11 @@ public PopupSlider() {
slider.addChangeListener(this);
}
+ /**
+ * Handles state changes in the slider by adjusting the zoom level of the {@code ScrollView}
+ *
+ * @param e the {@code ChangeEvent} indicating that the slider's state has changed
+ */
public void stateChanged(ChangeEvent e) {
if (slider.getValueIsAdjusting()) {
parent.zoomTo((double) slider.getValue() / 100.0);
diff --git a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java
index 934d31c53..66af90abd 100644
--- a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java
+++ b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java
@@ -5,6 +5,10 @@
import java.awt.Graphics2D;
import javax.swing.*;
+/**
+ * The {@code ZoomablePane} class is used to display components in a zoomable and scalable manner.
+ * It uses {@code ScrollView} to handle scaling and drawing of the content.
+ */
public class ZoomablePane extends JLayeredPane {
private ScrollView viewer;
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java
index ca03f1e25..fa3ec70b7 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java
@@ -11,6 +11,10 @@
import java.awt.*;
import java.util.ArrayList;
+/**
+ * An abstract class representing a view for a board in the puzzle game.
+ * It handles the visual representation and user interactions with the board elements.
+ */
public abstract class BoardView extends ScrollView implements IBoardListener {
protected TreeElement treeElement;
protected Board board;
@@ -125,6 +129,9 @@ public void setBoard(Board board) {
}
}
+ /**
+ * Configures the view to handle case interactions
+ */
protected void setCasePickable() {
CaseBoard caseBoard = (CaseBoard) board;
Board baseBoard = caseBoard.getBaseBoard();
@@ -183,15 +190,26 @@ public ArrayList getElementViews() {
return elementViews;
}
+ /**
+ * Gets the ElementController associated with this board view.
+ *
+ * @return the ElementController
+ */
public ElementController getElementController() {
return elementController;
}
+
@Override
public void draw(Graphics2D graphics2D) {
drawBoard(graphics2D);
}
+ /**
+ * Draws the board and its elements.
+ *
+ * @param graphics2D the Graphics2D context used for drawing
+ */
public void drawBoard(Graphics2D graphics2D) {
for (ElementView element : elementViews) {
element.draw(graphics2D);
@@ -208,5 +226,10 @@ public void onBoardDataChanged(PuzzleElement puzzleElement) {
repaint();
}
+ /**
+ * Gets the selection popup menu for this board view.
+ *
+ * @return the DataSelectionView associated with this view
+ */
public abstract DataSelectionView getSelectionPopupMenu();
}
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java
index cedfa08fe..a3d82b461 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java
@@ -5,8 +5,17 @@
import javax.swing.*;
import javax.swing.border.BevelBorder;
+/**
+ * DataSelectionView is a popup menu used for selecting data elements.
+ * It extends JPopupMenu and is styled with a gray background and a raised bevel border.
+ */
public class DataSelectionView extends JPopupMenu {
+ /**
+ * Constructs a DataSelectionView with the given controller.
+ *
+ * @param controller The ElementController to handle UI events.
+ */
public DataSelectionView(ElementController controller) {
setBackground(Color.GRAY);
setBorder(new BevelBorder(BevelBorder.RAISED));
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java
index 8e6f2cb18..9ad4132d6 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java
@@ -3,25 +3,48 @@
import java.awt.*;
import java.util.ArrayList;
+/**
+ * ElementSelection manages the selection and hover states of ElementViews.
+ * It maintains a list of selected elements, the currently hovered element, and the mouse point location.
+ */
public class ElementSelection {
private ArrayList selection;
private ElementView hover;
private Point mousePoint;
+ /**
+ * Constructs an ElementSelection instance with an empty selection and no hover or mouse point
+ */
public ElementSelection() {
this.selection = new ArrayList<>();
this.hover = null;
this.mousePoint = null;
}
+ /**
+ * Gets the list of currently selected ElementViews.
+ *
+ * @return the list of selected ElementViews
+ */
public ArrayList getSelection() {
return selection;
}
+ /**
+ * Gets the first ElementView in the selection, or null if the selection is empty.
+ *
+ * @return the first selected ElementView, or null if there are no selections
+ */
public ElementView getFirstSelection() {
return selection.size() == 0 ? null : selection.get(0);
}
+ /**
+ * Toggles the selection state of an ElementView.
+ * If the ElementView is currently selected, it is deselected. Otherwise, it is selected.
+ *
+ * @param elementView the ElementView to toggle
+ */
public void toggleSelection(ElementView elementView) {
if (selection.contains(elementView)) {
selection.remove(elementView);
@@ -32,12 +55,20 @@ public void toggleSelection(ElementView elementView) {
}
}
+ /**
+ * Sets a new selection, clearing the previous selection and selecting the specified ElementView.
+ *
+ * @param elementView the ElementView to select
+ */
public void newSelection(ElementView elementView) {
clearSelection();
selection.add(elementView);
elementView.setSelected(true);
}
+ /**
+ * Clears the selection and deselects all ElementViews
+ */
public void clearSelection() {
for (ElementView elementView : selection) {
elementView.setSelected(false);
@@ -45,10 +76,20 @@ public void clearSelection() {
selection.clear();
}
+ /**
+ * Gets the currently hovered ElementView.
+ *
+ * @return the currently hovered ElementView, or null if no element is hovered
+ */
public ElementView getHover() {
return hover;
}
+ /**
+ * Sets a new hovered ElementView, updating the hover state of the previous and new elements.
+ *
+ * @param newHovered the new ElementView to be hovered
+ */
public void newHover(ElementView newHovered) {
newHovered.setHover(true);
if (hover != null) {
@@ -57,6 +98,9 @@ public void newHover(ElementView newHovered) {
hover = newHovered;
}
+ /**
+ * Clears the current hover state if there exists one
+ */
public void clearHover() {
if (hover != null) {
hover.setHover(false);
@@ -64,10 +108,20 @@ public void clearHover() {
}
}
+ /**
+ * Gets the current mouse point location.
+ *
+ * @return the current mouse point location
+ */
public Point getMousePoint() {
return mousePoint;
}
+ /**
+ * Sets the mouse point location.
+ *
+ * @param point the new mouse point location
+ */
public void setMousePoint(Point point) {
this.mousePoint = point;
}
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java
index 83b2cb099..ad6cd3d3f 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java
@@ -9,6 +9,10 @@
import java.awt.image.BufferedImage;
import javax.swing.*;
+/**
+ * ElementView represents a visual representation of a PuzzleElement.
+ * It handles drawing, selection, hover states, and interaction with the PuzzleElement.
+ */
public abstract class ElementView implements Shape {
protected int index;
protected Point location;
@@ -73,6 +77,11 @@ public void draw(Graphics2D graphics2D) {
}
}
+ /**
+ * Draws the basic element representation (e.g., border, text) on the provided Graphics2D context.
+ *
+ * @param graphics2D the Graphics2D context to use for drawing
+ */
public void drawElement(Graphics2D graphics2D) {
graphics2D.setStroke(new BasicStroke(1));
graphics2D.draw(
@@ -87,8 +96,19 @@ public void drawElement(Graphics2D graphics2D) {
graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText);
}
+ /**
+ * Draws additional elements for given PuzzleElements (default implementation does nothing).
+ * Overriden in some puzzle element views.
+ *
+ * @param graphics2D the Graphics2D context to use for drawing
+ */
public void drawGiven(Graphics2D graphics2D) {}
+ /**
+ * Draws a hover effect on the ElementView.
+ *
+ * @param graphics2D the Graphics2D context to use for drawing
+ */
public void drawHover(Graphics2D graphics2D) {
graphics2D.setColor(hoverColor);
graphics2D.setStroke(new BasicStroke(2));
@@ -97,6 +117,11 @@ public void drawHover(Graphics2D graphics2D) {
location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3));
}
+ /**
+ * Draws a modified effect on the ElementView.
+ *
+ * @param graphics2D the Graphics2D context to use for drawing
+ */
public void drawModified(Graphics2D graphics2D) {
graphics2D.setColor(puzzleElement.isValid() ? modifiedColor : invalidColor);
graphics2D.setStroke(new BasicStroke(2));
@@ -105,6 +130,11 @@ public void drawModified(Graphics2D graphics2D) {
location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3));
}
+ /**
+ * Draws a case rule picker on the ElementView.
+ *
+ * @param graphics2D the Graphics2D context to use for drawing
+ */
public void drawCase(Graphics2D graphics2D) {
graphics2D.setColor(caseColor);
graphics2D.fill(
@@ -112,6 +142,11 @@ public void drawCase(Graphics2D graphics2D) {
location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3));
}
+ /**
+ * Creates an image representation of the ElementView.
+ *
+ * @return a BufferedImage of the ElementView
+ */
public BufferedImage getImage() {
BufferedImage image =
new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
@@ -193,10 +228,20 @@ public void setPuzzleElement(PuzzleElement data) {
this.puzzleElement = data;
}
+ /**
+ * Checks if the case picker should be shown for this ElementView
+ *
+ * @return true if the case picker should be shown, false otherwise
+ */
public boolean isShowCasePicker() {
return showCasePicker;
}
+ /**
+ * Sets whether the case picker should be shown for this ElementView
+ *
+ * @param showCasePicker true if the case picker should be shown, false otherwise
+ */
public void setShowCasePicker(boolean showCasePicker) {
this.showCasePicker = showCasePicker;
}
@@ -281,6 +326,13 @@ public JMenuItem getSelectionMenuItem() {
return item;
}
+ /**
+ * Determines if the specified point (x, y) is within the bounds of this ElementView
+ *
+ * @param x the x-coordinate of the point to check
+ * @param y the y-coordinate of the point to check
+ * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y) {
return x >= location.x
@@ -289,17 +341,38 @@ public boolean contains(double x, double y) {
&& y <= location.y + size.height;
}
+ /**
+ * Determines if the specified Point2D object is within the bounds of this ElementView
+ *
+ * @param point the Point2D object representing the point to check
+ * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean contains(Point2D point) {
return contains(point.getX(), point.getY());
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this ElementView.
+ *
+ * @param x The x-coordinate of the rectangle to check
+ * @param y The y-coordinate of the rectangle to check
+ * @param width The width of the rectangle to check
+ * @param height The height of the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean intersects(double x, double y, double width, double height) {
return (x + width >= location.x && x <= location.x + size.width)
|| (y + height >= location.y && y <= location.y + size.height);
}
+ /**
+ * Determines if the specified Rectangle2D object intersects with the bounds of this ElementView.
+ *
+ * @param rectangle2D the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean intersects(Rectangle2D rectangle2D) {
return intersects(
@@ -309,12 +382,27 @@ public boolean intersects(Rectangle2D rectangle2D) {
rectangle2D.getHeight());
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this ElementView
+ *
+ * @param x the x-coordinate of the rectangle to check
+ * @param y the y-coordinate of the rectangle to check
+ * @param width the width of the rectangle to check
+ * @param height the height of the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y, double width, double height) {
return (x + width >= location.x && x <= location.x + size.width)
&& (y + height >= location.y && y <= location.y + size.height);
}
+ /**
+ * Determines if the specified Rectangle2D object is entirely contained within the bounds of this ElementView.
+ *
+ * @param rectangle2D the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise
+ */
@Override
public boolean contains(Rectangle2D rectangle2D) {
return contains(
@@ -324,22 +412,48 @@ public boolean contains(Rectangle2D rectangle2D) {
rectangle2D.getHeight());
}
+
+ /**
+ * Returns an iterator over the path geometry of this ElementView. The iterator provides access to the path's
+ * segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @return a PathIterator that iterates over the path geometry of this ElementView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at) {
return new Rectangle(location.x, location.y, size.width, size.height).getPathIterator(at);
}
+ /**
+ * Returns an iterator over the path geometry of this ElementView with the specified flatness. The iterator provides
+ * access to the path's segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @param flatness the maximum distance that the line segments can deviate from the true path
+ * @return a PathIterator that iterates over the path geometry of this ElementView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return new Rectangle(location.x, location.y, size.width, size.height)
.getPathIterator(at, flatness);
}
+ /**
+ * Returns the bounding rectangle of this ElementView
+ *
+ * @return a Rectangle representing the bounding box of this ElementView
+ */
@Override
public Rectangle getBounds() {
return new Rectangle(location.x, location.y, size.width, size.height);
}
+ /**
+ * Returns the bounding rectangle of this ElementView as a Rectangle2D
+ *
+ * @return a Rectangle2D representing the bounding box of this ElementView
+ */
@Override
public Rectangle2D getBounds2D() {
return new Rectangle(location.x, location.y, size.width, size.height);
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java
index c40303192..1baa34b3a 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java
@@ -5,6 +5,11 @@
import java.awt.Color;
import java.awt.Dimension;
+/**
+ * A view class for a grid-based board that displays elements in a grid layout.
+ * This class extends BoardView and is responsible for managing and rendering
+ * grid-based elements.
+ */
public class GridBoardView extends BoardView {
protected Dimension gridSize;
protected Dimension elementSize;
@@ -51,6 +56,14 @@ public GridElementView getElement(int index) {
return null;
}
+ /**
+ * Retrieves the GridElementView at the specified grid coordinates (xIndex, yIndex).
+ * Returns null if the coordinates are out of bounds.
+ *
+ * @param xIndex the x-coordinate (column) of the element view to retrieve
+ * @param yIndex the y-coordinate (row) of the element view to retrieve
+ * @return the GridElementView at the specified coordinates, or null if out of bounds
+ */
public GridElementView getElement(int xIndex, int yIndex) {
if (xIndex < gridSize.width && yIndex < gridSize.height) {
return (GridElementView) elementViews.get(yIndex * gridSize.width + xIndex);
@@ -58,7 +71,10 @@ public GridElementView getElement(int xIndex, int yIndex) {
return null;
}
- /** Initializes the initial dimension of the viewport for the GridBoardView */
+ /**
+ * Initializes the initial dimension of the viewport for the GridBoardView.
+ * Sets the size of the board view and adjusts the zoom to fit.
+ */
@Override
public void initSize() {
setSize(getProperSize());
@@ -66,9 +82,9 @@ public void initSize() {
}
/**
- * Helper method to determine the proper dimension of the grid view
+ * Determines the proper dimension of the grid view based on grid size and element size.
*
- * @return proper dimension of the grid view
+ * @return the dimension of the grid view
*/
protected Dimension getProperSize() {
Dimension boardViewSize = new Dimension();
@@ -77,10 +93,21 @@ protected Dimension getProperSize() {
return boardViewSize;
}
+ /**
+ * Retrieves the selection popup menu for data selection.
+ * Currently returns null as there is no implementation.
+ *
+ * @return null
+ */
public DataSelectionView getSelectionPopupMenu() {
return null;
}
+ /**
+ * Gets the size of each element in the grid
+ *
+ * @return the dimension of each element in the grid
+ */
public Dimension getElementSize() {
return this.elementSize;
}
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java
index 440b3a693..31e8fcd6c 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java
@@ -2,6 +2,11 @@
import edu.rpi.legup.model.gameboard.GridCell;
+/**
+ * A view class for a grid cell element in the board.
+ * This class extends ElementView and represents a specific type of element view
+ * associated with a GridCell.
+ */
public class GridElementView extends ElementView {
public GridElementView(GridCell cell) {
super(cell);
diff --git a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java
index b2d3e31dd..15deb86d1 100644
--- a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java
+++ b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java
@@ -3,28 +3,68 @@
import edu.rpi.legup.model.gameboard.PuzzleElement;
import javax.swing.*;
+/**
+ * A menu item view class that represents a selectable item in a menu, associated with a PuzzleElement.
+ * This class extends JMenuItem and provides additional functionality to
+ * handle PuzzleElement data.
+ */
public class SelectionItemView extends JMenuItem {
private PuzzleElement data;
+ /**
+ * Constructs a SelectionItemView with the specified PuzzleElement and icon.
+ * Initializes the menu item with the given icon and associates it with the
+ * provided PuzzleElement.
+ *
+ * @param data the PuzzleElement associated with this menu item
+ * @param icon the icon to be displayed on the menu item
+ */
public SelectionItemView(PuzzleElement data, Icon icon) {
super(icon);
this.data = data;
}
+ /**
+ * Constructs a SelectionItemView with the specified PuzzleElement and display text.
+ * Initializes the menu item with the given display text and associates it with the
+ * provided PuzzleElement.
+ *
+ * @param data the PuzzleElement associated with this menu item
+ * @param display the text to be displayed on the menu item
+ */
public SelectionItemView(PuzzleElement data, String display) {
super(display);
this.data = data;
}
+ /**
+ * Constructs a SelectionItemView with the specified PuzzleElement and display integer.
+ * Initializes the menu item with the integer converted to a string and associates it with
+ * the provided PuzzleElement.
+ *
+ * @param data the PuzzleElement associated with this menu item
+ * @param display the integer to be displayed on the menu item
+ */
public SelectionItemView(PuzzleElement data, int display) {
super(String.valueOf(display));
this.data = data;
}
+ /**
+ * Constructs a SelectionItemView with the specified PuzzleElement.
+ * Initializes the menu item with the data's integer representation as display text.
+ *
+ * @param data the PuzzleElement associated with this menu item
+ */
public SelectionItemView(PuzzleElement data) {
this(data, (Integer) data.getData());
}
+ /**
+ * Gets the PuzzleElement associated with this menu item
+ *
+ * @return the PuzzleElement associated with this menu item
+ */
public PuzzleElement getData() {
return data;
}
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java
index 1fb0a16ab..849c5c145 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java
@@ -2,6 +2,12 @@
import javax.swing.ImageIcon;
+/**
+ * The {@code CaseRulePanel} class is a specialized panel that represents case rules
+ * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides
+ * specific functionality and UI components related to case rules.
+ * This class initializes with an icon and name that are specific to case rules.
+ */
public class CaseRulePanel extends RulePanel {
/**
* CaseRulePanel Constructor creates a CaseRulePanel
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java
index f695491fb..5bed7e17d 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java
@@ -2,7 +2,14 @@
import javax.swing.*;
-public class ContradictionRulePanel extends RulePanel {
+/**
+ * The {@code ContradictionRulePanel} class is a specialized panel that represents contradiction rules
+ * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides
+ * specific functionality and UI components related to contradiction rules.
+ * This class initializes with an icon and name that are specific to contradiction rules.
+ */
+
+ public class ContradictionRulePanel extends RulePanel {
/**
* ContradictionRulePanel Constructor creates a ContradictionRulePanel
*
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java
index 2795f2df7..c1562eb70 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java
@@ -4,7 +4,13 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-public class DirectRulePanel extends RulePanel {
+/**
+ * The {@code DirectRulePanel} class is a specialized panel that represents direct rules
+ * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides
+ * specific functionality and UI components related to direct rules.
+ * This class initializes with an icon and name that are specific to direct rules.
+ */
+ public class DirectRulePanel extends RulePanel {
private static final Logger LOGGER = LogManager.getLogger(DirectRulePanel.class.getName());
/**
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java
index e9c274250..7222603bc 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java
@@ -3,6 +3,11 @@
import edu.rpi.legup.model.rules.Rule;
import javax.swing.*;
+/**
+ * The {@code RuleButton} class is a custom button that represents a rule in the user interface.
+ * It extends {@link JButton} and is designed to display a rule's name and icon.
+ * The button is initialized with a {@link Rule} object, which provides the name and icon for the button.
+ */
public class RuleButton extends JButton {
private Rule rule;
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java
index 6279f93a4..3131f474d 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java
@@ -10,6 +10,13 @@
import javax.swing.*;
import javax.swing.border.TitledBorder;
+/**
+ * The {@code RuleFrame} class is a panel that contains and manages multiple rule-related panels
+ * within a tabbed interface. It extends {@link JPanel} and organizes the display of various rule types
+ * such as direct rules, contradiction rules, and case rules.
+ * The frame uses a {@link JTabbedPane} to allow users to switch between different rule panels.
+ * It also includes a search bar panel and a status label for displaying additional information.
+ */
public class RuleFrame extends JPanel {
private static final String checkBox = " \u2714 ";
private static final String xBox = " \u2718 ";
@@ -28,6 +35,12 @@ public class RuleFrame extends JPanel {
private RuleController controller;
+ /**
+ * Constructs a new {@code RuleFrame} instance.
+ * Initializes the frame with tabs for the different rule panels, a search bar panel, and a status label.
+ *
+ * @param controller the {@link RuleController} instance that manages the rules for this frame
+ */
public RuleFrame(RuleController controller) {
MaterialTabbedPaneUI tabOverride =
@@ -118,7 +131,7 @@ public void resetSize() {
/**
* Set the status label to a value. Use resetStatus to clear it.
*
- * @param check true iff we want a check box, if false we'll have a red x box
+ * @param check true if we want a checkbox, if false we'll have a red x box
* @param text the text we're setting the label to display
*/
public void setStatus(boolean check, String text) {
@@ -156,22 +169,47 @@ public RuleController getController() {
return controller;
}
+ /**
+ * Gets the JTabbedPane used in this frame
+ *
+ * @return the JTabbedPane instance
+ */
public JTabbedPane getTabbedPane() {
return tabbedPane;
}
+ /**
+ * Gets the {@code DirectRulePanel} contained in this frame
+ *
+ * @return the {@link DirectRulePanel} instance
+ */
public DirectRulePanel getDirectRulePanel() {
return DirectRulePanel;
}
+ /**
+ * Gets the {@code CaseRulePanel} contained in this frame
+ *
+ * @return the {@link CaseRulePanel} instance
+ */
public CaseRulePanel getCasePanel() {
return casePanel;
}
+ /**
+ * Gets the {@code ContradictionRulePanel} contained in this frame
+ *
+ * @return the {@link ContradictionRulePanel} instance
+ */
public ContradictionRulePanel getContradictionPanel() {
return contradictionPanel;
}
+ /**
+ * Gets the {@code SearchBarPanel} contained in this frame
+ *
+ * @return the {@link SearchBarPanel} instance
+ */
public SearchBarPanel getSearchPanel() {
return searchPanel;
}
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java
index 5d985d5c2..4c9ebf882 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java
@@ -9,6 +9,10 @@
import java.util.List;
import javax.swing.*;
+/**
+ * Abstract base class for panels displaying rules. Each subclass will represent a specific type
+ * of rule panel (e.g., DirectRulePanel, CaseRulePanel).
+ */
public abstract class RulePanel extends JPanel {
protected ImageIcon icon;
protected String name;
@@ -32,7 +36,7 @@ public RulePanel(RuleFrame ruleFrame) {
}
/**
- * Gets the rule rule buttons
+ * Gets the array of rule buttons
*
* @return rule ruleButtons
*/
@@ -55,20 +59,30 @@ public void setRules(List extends Rule> rules) {
Rule rule = rules.get(i);
ruleButtons[i] = new RuleButton(rule);
- ruleButtons[i].setPreferredSize(
- new Dimension(150, 150)); // adjust the size of each RuleButton
+ ruleButtons[i].setPreferredSize(new Dimension(150, 150)); // adjust the size of each RuleButton
+
+ if (rule.getRuleName().length() > 18) {
+ ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 11));
+ }
+ if (rule.getRuleName().length() > 20) {
+ ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 10));
+ }
+ System.out.println(ruleButtons[i].getFont().getName());
+
ruleButtons[i].setHorizontalTextPosition(JButton.CENTER);
ruleButtons[i].setVerticalTextPosition(JButton.BOTTOM);
ruleFrame.getButtonGroup().add(ruleButtons[i]);
- ruleButtons[i].setToolTipText(
- rule.getRuleName() + ": " + rule.getDescription()); // showing description
+ ruleButtons[i].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); // showing description
ruleButtons[i].addActionListener(ruleFrame.getController());
add(ruleButtons[i]);
}
revalidate();
}
+ /**
+ * Updates the rules displayed by reloading images and setting the rules again.
+ */
public void updateRules() {
for (Rule rule : rules) {
rule.loadImage();
@@ -324,28 +338,58 @@ public List extends Rule> getRules() {
return rules;
}
+ /**
+ * Gets the icon associated with this panel
+ *
+ * @return The ImageIcon associated with this panel
+ */
public ImageIcon getIcon() {
return icon;
}
+ /**
+ * Sets the icon for this panel
+ *
+ * @return the ImageIcon associated with this panel
+ */
public void setIcon(ImageIcon icon) {
this.icon = icon;
}
+ /**
+ * Gets the name of this panel
+ *
+ * @return the name of this panel in a String
+ */
@Override
public String getName() {
return name;
}
+ /**
+ * Sets the name of this panel
+ *
+ * @param name the name to set for this panel
+ */
@Override
public void setName(String name) {
this.name = name;
}
+ /**
+ * Gets the tooltip text associated with this panel
+ *
+ * @return the tooltip text of this panel
+ */
public String getToolTip() {
return toolTip;
}
+ /**
+ * Sets the tooltip text for this panel
+ *
+ * @param toolTip the tooltip text to set for this panel
+ */
public void setToolTip(String toolTip) {
this.toolTip = toolTip;
}
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java
index aba4707cd..842859ce2 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java
@@ -2,6 +2,11 @@
import javax.swing.*;
+
+/**
+ * The {@code SearchBarPanel} class creates a panel that allows users to search for rules within the rule frame.
+ * This panel provides a search bar for entering rule names and finding corresponding rules.
+ */
public class SearchBarPanel extends RulePanel {
/**
* SearchBarPanel Constructor creates a SearchBarPanel
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java
index 33c04717d..228e69950 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java
@@ -4,6 +4,12 @@
import edu.rpi.legup.model.tree.TreeElementType;
import java.awt.*;
+/**
+ * Abstract base class for views of tree elements in the tree structure.
+ * This class implements the Shape interface to support custom drawing and interaction
+ * with tree elements.
+ * It holds properties for rendering, interaction, and layout of the tree elements.
+ */
public abstract class TreeElementView implements Shape {
protected TreeElement treeElement;
protected double span;
@@ -36,7 +42,7 @@ protected TreeElementView(TreeElementType type, TreeElement treeElement) {
public abstract void draw(Graphics2D graphics2D);
/**
- * Gets the span for the sub tree rooted at this view
+ * Gets the span for the subtree rooted at this view
*
* @return span bounded y span
*/
@@ -45,7 +51,7 @@ public double getSpan() {
}
/**
- * Sets the span for the sub tree rooted at this view.
+ * Sets the span for the subtree rooted at this view.
*
* @param span bounded y span
*/
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java
index 990d96620..0e2a31bbf 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java
@@ -7,6 +7,12 @@
import java.awt.geom.*;
import java.util.ArrayList;
+/**
+ * Represents a view of a tree node in the tree structure.
+ * This class extends {@link TreeElementView} and provides specific rendering and interaction
+ * functionality for tree nodes. It includes visual properties and methods to manage the
+ * node's appearance, location, and its relationships with other nodes.
+ */
public class TreeNodeView extends TreeElementView {
static final int RADIUS = 25;
static final int DIAMETER = 2 * RADIUS;
@@ -260,51 +266,119 @@ public int getRadius() {
return RADIUS;
}
+ /**
+ * Returns the bounding rectangle of this TreeNodeView
+ *
+ * @return a Rectangle representing the bounding box of this TreeNodeView
+ */
@Override
public Rectangle getBounds() {
return new Rectangle(location.x, location.y, DIAMETER, DIAMETER);
}
+ /**
+ * Returns the bounding rectangle of this TreeNodeView as a Rectangle2D
+ *
+ * @return a Rectangle2D representing the bounding box of this TreeNodeView
+ */
@Override
public Rectangle2D getBounds2D() {
return new Rectangle(location.x, location.y, DIAMETER, DIAMETER);
}
+ /**
+ * Determines if the specified point (x, y) is within the bounds of this TreeNodeView
+ *
+ * @param x the x-coordinate of the point to check
+ * @param y the y-coordinate of the point to check
+ * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y) {
return Math.sqrt(Math.pow(x - location.x, 2) + Math.pow(y - location.y, 2)) <= RADIUS;
}
+ /**
+ * Determines if the specified Point2D object is within the bounds of this TreeNodeView
+ *
+ * @param p the Point2D object representing the point to check
+ * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeNodeView.
+ *
+ * @param x The x-coordinate of the rectangle to check
+ * @param y The y-coordinate of the rectangle to check
+ * @param w The width of the rectangle to check
+ * @param h The height of the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean intersects(double x, double y, double w, double h) {
return false;
}
+ /**
+ * Determines if the specified Rectangle2D object intersects with the bounds of this TreeNodeView.
+ *
+ * @param r the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean intersects(Rectangle2D r) {
return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeNodeView
+ *
+ * @param x the x-coordinate of the rectangle to check
+ * @param y the y-coordinate of the rectangle to check
+ * @param w the width of the rectangle to check
+ * @param h the height of the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y, double w, double h) {
return false;
}
+ /**
+ * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeNodeView.
+ *
+ * @param r the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise
+ */
@Override
public boolean contains(Rectangle2D r) {
return false;
}
+ /**
+ * Returns an iterator over the path geometry of this TreeNodeView. The iterator provides access to the path's
+ * segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @return a PathIterator that iterates over the path geometry of this TreeNodeView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at) {
return null;
}
+ /**
+ * Returns an iterator over the path geometry of this TreeNodeView with the specified flatness. The iterator provides
+ * access to the path's segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @param flatness the maximum distance that the line segments can deviate from the true path
+ * @return a PathIterator that iterates over the path geometry of this TreeNodeView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return null;
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java
index b6a29f2b5..4bef664bd 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java
@@ -17,6 +17,12 @@
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
+
+/**
+ * {@code TreePanel} is a JPanel that manages and displays a tree view with associated toolbar and status information.
+ * It provides methods to interact with the tree view, such as adding, deleting, and merging tree elements,
+ * and updating the status based on actions performed.
+ */
public class TreePanel extends JPanel {
public boolean modifiedSinceSave = false;
public boolean modifiedSinceUndoPush = false;
@@ -29,6 +35,9 @@ public class TreePanel extends JPanel {
private JLabel status;
+ /**
+ * Constructs a {@code TreePanel} and initializes the UI components.
+ */
public TreePanel(/*LegupUI legupUI*/ ) {
// this.legupUI = legupUI;
@@ -60,10 +69,20 @@ public TreePanel(/*LegupUI legupUI*/ ) {
updateStatusTimer = 0;
}
+ /**
+ * Repaints the tree view with the provided {@link Tree} object
+ *
+ * @param tree the {@link Tree} object to update the view with
+ */
public void repaintTreeView(Tree tree) {
treeView.updateTreeView(tree);
}
+ /**
+ * Updates the status of the panel based on changes to the {@link Board}
+ *
+ * @param board the {@link Board} object representing the current board state
+ */
public void boardDataChanged(Board board) {
modifiedSinceSave = true;
modifiedSinceUndoPush = true;
@@ -71,6 +90,11 @@ public void boardDataChanged(Board board) {
// colorTransitions();
}
+ /**
+ * Updates the status display based on the status timer.
+ * If the timer is greater than 0, the status will not be updated.
+ * Otherwise, it clears the status text.
+ */
public void updateStatus() {
updateStatusTimer = ((updateStatusTimer - 1) > 0) ? (updateStatusTimer - 1) : 0;
if (updateStatusTimer > 0) {
@@ -79,22 +103,41 @@ public void updateStatus() {
this.status.setText("");
}
+ /**
+ * Updates the status display with the given status string
+ *
+ * @param statusString the status string to display
+ */
public void updateStatus(String statusString) {
status.setForeground(Color.BLACK);
status.setFont(MaterialFonts.REGULAR);
status.setText(statusString);
}
+ /**
+ * Updates the status display as an error with an error message
+ *
+ * @param error the error message to display
+ */
public void updateError(String error) {
status.setForeground(Color.RED);
status.setFont(MaterialFonts.ITALIC);
status.setText(error);
}
+ /**
+ * Gets the {@link TreeView} instance associated with this panel
+ *
+ * @return the {@link TreeView} instance
+ */
public TreeView getTreeView() {
return treeView;
}
+ /**
+ * Adds a new tree element by executing an {@link AddTreeElementCommand}.
+ * If the command cannot be executed, it updates the status display with an error and error message.
+ */
public void add() {
TreeViewSelection selection = treeView.getSelection();
@@ -107,6 +150,10 @@ public void add() {
}
}
+ /**
+ * Deletes the selected tree element by executing a {@link DeleteTreeElementCommand}.
+ * If the command cannot be executed, it updates the status display with an error and an error message.
+ */
public void delete() {
TreeViewSelection selection = treeView.getSelection();
@@ -119,6 +166,10 @@ public void delete() {
}
}
+ /**
+ * Merges selected tree elements by executing a {@link MergeCommand}.
+ * If the command cannot be executed, it updates the status display with an error and an error message.
+ */
public void merge() {
TreeViewSelection selection = treeView.getSelection();
@@ -131,6 +182,10 @@ public void merge() {
}
}
+ /**
+ * Toggles the collapsed state of the selected tree elements.
+ * If an element is collapsed, it will be expanded, and vice versa.
+ */
public void collapse() {
TreeViewSelection selection = treeView.getSelection();
for (TreeElementView view : selection.getSelectedViews()) {
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java
index 002092155..214c735df 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java
@@ -3,11 +3,20 @@
import java.awt.Dimension;
import javax.swing.*;
+/**
+ * {@code TreeToolBarButton} is a JButton that represents a button in the tree toolbar.
+ */
public class TreeToolBarButton extends JButton {
private TreeToolBarName name;
private final Dimension MINIMUM_DIMENSION = new Dimension(60, 60);
+ /**
+ * Constructs a {@code TreeToolBarButton} with the specified icon and name.
+ *
+ * @param imageIcon the {@link ImageIcon} to be displayed on the button
+ * @param name the {@link TreeToolBarName} associated with this button
+ */
public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) {
super(imageIcon);
this.name = name;
@@ -16,6 +25,11 @@ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) {
this.setFocusPainted(false);
}
+ /**
+ * Gets the {@link TreeToolBarName} associated with this button
+ *
+ * @return the {@link TreeToolBarName} associated with this button
+ */
public TreeToolBarName getToolBarName() {
return name;
}
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java
index c805021be..3aec664be 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java
@@ -1,5 +1,9 @@
package edu.rpi.legup.ui.proofeditorui.treeview;
+/**
+ * {@code TreeToolBarName} defines the names of actions represented by buttons in the tree toolbar.
+ * These actions are used for managing tree elements within the UI.
+ */
public enum TreeToolBarName {
ADD_CHILD,
DEL_CHILD,
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java
index 8f3ebfc23..500ed29c5 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java
@@ -3,6 +3,11 @@
import java.awt.*;
import javax.swing.*;
+
+/**
+ * {@code TreeToolbarPanel} is a JPanel that provides a toolbar for managing tree elements in the tree view.
+ * It includes buttons for adding, deleting, merging, and collapsing nodes.
+ */
public class TreeToolbarPanel extends JPanel {
private TreePanel treePanel;
private TreeToolBarButton addChild, delChild, merge, collapse;
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java
index b022ac596..25c67bb5a 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java
@@ -10,6 +10,11 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * {@code TreeTransitionView} is a visual representation of a tree transition in the tree view.
+ * It extends TreeElementView and displays a transition arrow between tree nodes and handles various
+ * visual states such as selection, hover, and correctness.
+ */
public class TreeTransitionView extends TreeElementView {
static final int RADIUS = 25;
static final int DIAMETER = 2 * RADIUS;
@@ -266,87 +271,165 @@ public void removeParentView(TreeNodeView nodeView) {
}
}
- public Point getEndPoint() {
- return endPoint;
- }
-
- public void setEndPoint(Point endPoint) {
- this.endPoint = endPoint;
- }
-
+ /**
+ * Gets the x-coordinate of the end point of the transition arrow
+ *
+ * @return the x-coordinate of the end point
+ */
public int getEndX() {
return endPoint.x;
}
+ /**
+ * Sets the x-coordinate of the end point of the transition arrow
+ *
+ * @param x the new x-coordinate of the end point
+ */
public void setEndX(int x) {
this.endPoint.x = x;
}
+ /**
+ * Gets the y-coordinate of the end point of the transition arrow
+ *
+ * @return the y-coordinate of the end point
+ */
public int getEndY() {
return endPoint.y;
}
+ /**
+ * Sets the y-coordinate of the end point of the transition arrow
+ *
+ * @param y the new y-coordinate of the end point
+ */
public void setEndY(int y) {
this.endPoint.y = y;
}
- public List getLineStartPoints() {
- return lineStartPoints;
- }
-
- public void setLineStartPoints(List lineStartPoints) {
- this.lineStartPoints = lineStartPoints;
- }
-
+ /**
+ * Gets the start point at the specified index from the list of start points
+ *
+ * @param index the index of the start point to retrieve
+ * @return the start point at the specified index, or null if the index is out of range
+ */
public Point getLineStartPoint(int index) {
return index < lineStartPoints.size() ? lineStartPoints.get(index) : null;
}
+ /**
+ * Returns the bounding rectangle of this TreeTransitionView
+ *
+ * @return a Rectangle representing the bounding box of this TreeTransitionView
+ */
@Override
public Rectangle getBounds() {
return arrowhead.getBounds();
}
+ /**
+ * Returns the bounding rectangle of this TreeTransitionView as a Rectangle2D
+ *
+ * @return a Rectangle2D representing the bounding box of this TreeTransitionView
+ */
@Override
public Rectangle2D getBounds2D() {
return arrowhead.getBounds2D();
}
+ /**
+ * Determines if the specified point (x, y) is within the bounds of this TreeTransitionView
+ *
+ * @param x the x-coordinate of the point to check
+ * @param y the y-coordinate of the point to check
+ * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y) {
return arrowhead.contains(x, y);
}
+ /**
+ * Determines if the specified Point2D object is within the bounds of this TreeTransitionView
+ *
+ * @param p the Point2D object representing the point to check
+ * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean contains(Point2D p) {
return arrowhead != null && arrowhead.contains(p);
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeTransitionView.
+ *
+ * @param x The x-coordinate of the rectangle to check
+ * @param y The y-coordinate of the rectangle to check
+ * @param w The width of the rectangle to check
+ * @param h The height of the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean intersects(double x, double y, double w, double h) {
return arrowhead.intersects(x, y, w, h);
}
+ /**
+ * Determines if the specified Rectangle2D object intersects with the bounds of this TreeTransitionView.
+ *
+ * @param r the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean intersects(Rectangle2D r) {
return arrowhead.intersects(r);
}
+ /**
+ * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeTransitionView
+ *
+ * @param x the x-coordinate of the rectangle to check
+ * @param y the y-coordinate of the rectangle to check
+ * @param w the width of the rectangle to check
+ * @param h the height of the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean contains(double x, double y, double w, double h) {
return arrowhead.contains(x, y, w, h);
}
+ /**
+ * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeTransitionView.
+ *
+ * @param r the Rectangle2D object representing the rectangle to check
+ * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise
+ */
@Override
public boolean contains(Rectangle2D r) {
return arrowhead.contains(r);
}
+ /**
+ * Returns an iterator over the path geometry of this TreeTransitionView. The iterator provides access to the path's
+ * segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @return a PathIterator that iterates over the path geometry of this TreeTransitionView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at) {
return arrowhead.getPathIterator(at);
}
+ /**
+ * Returns an iterator over the path geometry of this TreeTransitionView with the specified flatness. The iterator provides
+ * access to the path's segments and their coordinates, which can be used for rendering or hit testing.
+ *
+ * @param at the AffineTransform to apply to the path geometry
+ * @param flatness the maximum distance that the line segments can deviate from the true path
+ * @return a PathIterator that iterates over the path geometry of this TreeTransitionView
+ */
@Override
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return arrowhead.getPathIterator(at, flatness);
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java
index f491009b4..490cf1480 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java
@@ -26,6 +26,12 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+/**
+ * The {@code TreeView} class provides a graphical representation of a {@code Tree} structure,
+ * allowing interaction and visualization of tree elements, transitions, and selections.
+ * It extends {@code ScrollView} and implements {@code ITreeListener} to respond to updates
+ * in the tree structure.
+ */
public class TreeView extends ScrollView implements ITreeListener {
private static final Logger LOGGER = LogManager.getLogger(TreeView.class.getName());
@@ -51,6 +57,11 @@ public class TreeView extends ScrollView implements ITreeListener {
private TreeViewSelection selection;
+ /**
+ * Constructs a {@code TreeView} with the specified {@code TreeController}.
+ *
+ * @param treeController the {@code TreeController} used to manage tree operations
+ */
public TreeView(TreeController treeController) {
super(treeController);
currentStateBoxes = new ArrayList<>();
@@ -62,6 +73,11 @@ public TreeView(TreeController treeController) {
selection = new TreeViewSelection();
}
+ /**
+ * Gets the current tree view selection
+ *
+ * @return the {@code TreeViewSelection} object representing the current selection
+ */
public TreeViewSelection getSelection() {
return selection;
}
@@ -131,6 +147,11 @@ private TreeElementView getTreeElementView(Point point, TreeElementView elementV
return null;
}
+ /**
+ * Updates the tree view with the specified {@code Tree}
+ *
+ * @param tree the {@code Tree} to display in the view
+ */
public void updateTreeView(Tree tree) {
this.tree = tree;
if (selection.getSelectedViews().size() == 0) {
@@ -148,6 +169,9 @@ public void setTree(Tree tree) {
this.tree = tree;
}
+ /**
+ * Updates the size of the tree view based on the bounds of its tree
+ */
public void updateTreeSize() {
if (GameBoardFacade.getInstance().getTree() == null) {
return;
@@ -155,15 +179,23 @@ public void updateTreeSize() {
setSize(bounds.getSize());
}
+ /**
+ * Resets the view if the tree bounds have been modified
+ */
public void reset() {
if (bounds.x != 0 || bounds.y != 0) {
updateTreeSize();
}
}
+ /**
+ * Adjusts the zoom level to fit the entire tree within the viewport when
+ * the Resize Proof button is selected
+ */
public void zoomFit() {
- double fitWidth = (viewport.getWidth() - 8.0) / (getSize().width - 200);
- double fitHeight = (viewport.getHeight() - 8.0) / (getSize().height - 120);
+ final int MIN_HEIGHT = 200;
+ double fitWidth = (viewport.getWidth() - 7.0) / (getSize().width - 75);
+ double fitHeight = (viewport.getHeight()) / Math.max((getSize().height - 115), MIN_HEIGHT);
zoomTo(Math.min(fitWidth, fitHeight));
viewport.setViewPosition(new Point(0, viewport.getHeight() / 2));
}
@@ -212,6 +244,11 @@ public void layoutContainer(Container parent) {
};
}
+ /**
+ * Draws the tree view on the provided {@code Graphics2D} context
+ *
+ * @param graphics2D the {@code Graphics2D} context to draw on
+ */
public void draw(Graphics2D graphics2D) {
currentStateBoxes.clear();
Tree tree = GameBoardFacade.getInstance().getTree();
@@ -234,11 +271,20 @@ public void draw(Graphics2D graphics2D) {
}
}
+ /**
+ * Resets the zoom level to its default state and positions the viewport from the top-left corner
+ */
public void zoomReset() {
zoomTo(1.0);
viewport.setViewPosition(new Point(0, 0));
}
+ /**
+ * Recursively redraws the tree starting from the specified node view
+ *
+ * @param graphics2D the {@code Graphics2D} context to draw on
+ * @param nodeView the {@code TreeNodeView} to start drawing from
+ */
private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) {
if (nodeView != null) {
nodeView.draw(graphics2D);
@@ -249,6 +295,11 @@ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) {
}
}
+ /**
+ * Removes the specified {@code TreeElementView} from the tree view
+ *
+ * @param view the {@code TreeElementView} to remove
+ */
public void removeTreeElement(TreeElementView view) {
if (view.getType() == NODE) {
TreeNodeView nodeView = (TreeNodeView) view;
@@ -282,6 +333,9 @@ public void drawMouseOver(Graphics2D g) {
}
}
+ /**
+ * Resets the view by clearing the current tree, root node view, and selection
+ */
public void resetView() {
this.tree = null;
this.rootNodeView = null;
@@ -407,8 +461,17 @@ public TreeElementView getElementView(TreeElement element) {
return viewMap.get(element);
}
- private void removeTreeNode(TreeNode node) {
+ /**
+ * Removes the specified {@link TreeNode} and its associated views
+ *
+ * @param node the {@link TreeNode} to be removed
+ */
+ public void removeTreeNode(TreeNode node) {
viewMap.remove(node);
+ if (node.getChildren() != null) {
+ node.getChildren().forEach(t -> removeTreeTransition(t));
+ }
+
List children = node.getChildren();
// if child is a case rule, unlock ancestor elements
@@ -435,11 +498,13 @@ private void removeTreeNode(TreeNode node) {
}
// set modifiable if started modifiable
- boolean modifiable =
- tree.getRootNode()
- .getBoard()
- .getPuzzleElement(oldElement)
- .isModifiable();
+ boolean modifiable = false;
+ if (tree != null) {
+ tree.getRootNode()
+ .getBoard()
+ .getPuzzleElement(oldElement)
+ .isModifiable();
+ }
// unmodifiable if already modified
TreeNode modNode = ancestor.getParent().getParents().get(0);
@@ -457,22 +522,58 @@ private void removeTreeNode(TreeNode node) {
}
}
}
- node.getChildren().forEach(t -> removeTreeTransition(t));
}
- private void removeTreeTransition(TreeTransition trans) {
+ /**
+ * Removes the specified {@link TreeTransition} and its associated views
+ *
+ * @param trans the {@link TreeTransition} to be removed
+ */
+ public void removeTreeTransition(TreeTransition trans) {
viewMap.remove(trans);
if (trans.getChildNode() != null) {
removeTreeNode(trans.getChildNode());
}
+
+ // Update transition modifiability if removing a case rule
+ List parents = trans.getParents();
+ for (TreeNode parent : parents) {
+ // if transition is a case rule, unlock ancestor elements up until latest case rule or root node
+ boolean nextAncestorIsCaseRule = false;
+ Rule rule = trans.getRule();
+ if (rule instanceof CaseRule) {
+ List ancestors = parent.getAncestors();
+ for (int i = 0; i < ancestors.size(); i++) {
+ if (ancestors.get(i).getParent() == null) {
+ continue;
+ }
+ if (nextAncestorIsCaseRule) {
+ break;
+ }
+ for (PuzzleElement element : parent.getBoard().getPuzzleElements()) {
+ PuzzleElement curElement = ancestors.get(i).getParent().getBoard().getPuzzleElement(element);
+ if (!curElement.isModifiableCaseRule()) {
+ curElement.setModifiableCaseRule(true);
+ }
+ }
+ if (ancestors.get(i).getParent().getRule() instanceof CaseRule) {
+ nextAncestorIsCaseRule = true;
+ }
+ }
+ }
+ }
}
+ /**
+ * Adds the specified {@link TreeNode} and its associated views
+ *
+ * @param node the {@link TreeNode} to be added
+ */
private void addTreeNode(TreeNode node) {
TreeTransition parent = node.getParent();
-
TreeNodeView nodeView = new TreeNodeView(node);
- TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent);
+ TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent);
nodeView.setParentView(parentView);
parentView.setChildView(nodeView);
@@ -492,8 +593,7 @@ private void addTreeNode(TreeNode node) {
continue;
}
for (PuzzleElement element :
- caseRule.dependentElements(
- node.getBoard(), node.getChildren().get(0).getSelection())) {
+ caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) {
// increment and lock
PuzzleElement oldElement =
ancestor.getParent().getBoard().getPuzzleElement(element);
@@ -507,47 +607,50 @@ private void addTreeNode(TreeNode node) {
}
}
+ /**
+ * Adds the specified {@link TreeTransition} and its associated views
+ *
+ * @param trans The {@link TreeTransition} to be added
+ */
private void addTreeTransition(TreeTransition trans) {
List parents = trans.getParents();
-
TreeTransitionView transView = new TreeTransitionView(trans);
+
for (TreeNode parent : parents) {
TreeNodeView parentNodeView = (TreeNodeView) viewMap.get(parent);
transView.addParentView(parentNodeView);
parentNodeView.addChildrenView(transView);
+ viewMap.put(trans, transView);
+
// if transition is a new case rule, lock dependent ancestor elements
Rule rule = trans.getRule();
if (rule instanceof CaseRule && parent.getChildren().size() == 1) {
- CaseRule caseRule = (CaseRule) rule;
-
List ancestors = parent.getAncestors();
for (TreeNode ancestor : ancestors) {
// for all ancestors but root
if (ancestor.getParent() == null) {
continue;
}
- for (PuzzleElement element :
- caseRule.dependentElements(parent.getBoard(), trans.getSelection())) {
- // increment and lock
- PuzzleElement oldElement =
- ancestor.getParent().getBoard().getPuzzleElement(element);
- oldElement.setCasesDepended(oldElement.getCasesDepended() + 1);
- oldElement.setModifiable(false);
+
+ for (PuzzleElement element : parent.getBoard().getPuzzleElements()) {
+ PuzzleElement curElement = ancestor.getParent().getBoard().getPuzzleElement(element);
+ curElement.setModifiableCaseRule(false);
}
}
}
}
- viewMap.put(trans, transView);
-
if (trans.getChildNode() != null) {
addTreeNode(trans.getChildNode());
}
}
- /// New Draw Methods
-
+ /**
+ * Draws the tree using the provided {@link Graphics2D} object
+ *
+ * @param graphics2D the {@link Graphics2D} object used for drawing the tree
+ */
public void drawTree(Graphics2D graphics2D) {
if (tree == null) {
LOGGER.error("Unable to draw tree.");
@@ -573,6 +676,11 @@ public void drawTree(Graphics2D graphics2D) {
}
}
+ /**
+ * Creates views for the given {@link TreeNodeView} and its children
+ *
+ * @param nodeView the {@link TreeNodeView} for which to create views
+ */
public void createViews(TreeNodeView nodeView) {
if (nodeView != null) {
viewMap.put(nodeView.getTreeElement(), nodeView);
@@ -606,6 +714,14 @@ public void createViews(TreeNodeView nodeView) {
}
}
+ /**
+ * Calculates the layout locations (x and y coordinates) of the nodes in the tree.
+ * This method recursively traverses the tree and updates the positions of
+ * nodes and transitions based on their depth and parent relationships.
+ *
+ * @param nodeView the node view to calculate the positions for
+ * @param depth the depth of the node in the tree, used to calculate its x-coordinate
+ */
public void calculateViewLocations(TreeNodeView nodeView, int depth) {
nodeView.setDepth(depth);
int xLoc = (NODE_GAP_WIDTH + DIAMETER) * depth + DIAMETER;
@@ -711,6 +827,13 @@ public void calculateViewLocations(TreeNodeView nodeView, int depth) {
}
}
+ /**
+ * Calculates the span (height) required for the given view, including its children.
+ * This method recursively determines the span for nodes and transitions based on their
+ * children and the merging branches they belong to.
+ *
+ * @param view the view whose span is to be calculated
+ */
public void calcSpan(TreeElementView view) {
if (view.getType() == NODE) {
TreeNodeView nodeView = (TreeNodeView) view;
@@ -779,12 +902,12 @@ public void calcSpan(TreeElementView view) {
}
/**
- * Calculates the sub span of a given sub tree rooted at the specified view and stops at the
- * tree puzzleElement view specified as stop. Stop tree puzzleElement is NOT included in the
- * span calculation
+ * Calculates the span of a subtree rooted at the specified view, stopping at the given
+ * stop view. The stop view is not included in the span calculation.
*
- * @param view
- * @param stop
+ * @param view the root view of the subtree to calculate the span for
+ * @param stop the view at which to stop the span calculation. The stop view itself is
+ * not included in the span calculation
*/
private void subCalcSpan(TreeElementView view, TreeElementView stop) {
// safe-guard for infinite loop
@@ -859,12 +982,14 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) {
}
/**
- * Reorders branches such that merging branches are sequentially grouped together and
- * transitions are kept in relative order in the list of child transitions of the specified node
+ * Reorders the branches of a given node such that branches that merge are grouped together sequentially.
+ * Transitions are kept in their relative order based on their original positions in the list of child transitions
+ * of the specified node. This ensures that the visual representation of the branches and transitions maintains
+ * a logical and readable structure.
*
- * @param node root node of the branches
- * @param branches DisjointSets of the child branches of the specified node which determine
- * which branches merge
+ * @param node the root node whose branches are to be reordered
+ * @param branches a DisjointSets structure representing the merging relationships of the child branches of the
+ * specified node. This determines which branches should be grouped together
*/
private void reorderBranches(TreeNode node, DisjointSets branches) {
List children = node.getChildren();
diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java
index 71a65b49e..c7893b168 100644
--- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java
+++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java
@@ -4,6 +4,11 @@
import java.util.ArrayList;
import java.util.List;
+
+/**
+ * {@code TreeViewSelection} manages the selection and hover state of tree element views in a tree view.
+ * It maintains a list of selected views, tracks the currently hovered view, and manages the mouse position.
+ */
public class TreeViewSelection {
private ArrayList selectedViews;
private TreeElementView hover;
diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java
index e0524f84d..97c76919e 100644
--- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java
+++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java
@@ -14,52 +14,36 @@ public class ElementFrame extends JPanel {
private static final String htmlTail = "