The states include: - ZERO: Represents a cell with a value of 0 - ONE: Represents a cell with
+ * a value of 1 - UNKNOWN: Represents an empty cell
+ */
public enum BinaryType {
- ZERO,
- ONE,
- UNKNOWN;
+ ZERO, // Enum constant 0
+ ONE, // Enum constant 1
+ UNKNOWN; // Enum constant 2
+ /**
+ * The `toValue` method returns the ordinal value of the enum constant, which can be used to
+ * convert the enum to an integer representation.
+ */
public int toValue() {
return this.ordinal();
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java
index b11554f28..b428ce32c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java
@@ -7,6 +7,14 @@
public class BinaryView extends GridBoardView {
+ /**
+ * Creates and arranges the visual components for each cell in the binary puzzle. Initializes
+ * the view by setting up the board controller, binary controller, and the grid dimensions. For
+ * each cell in the BinaryBoard, it creates a corresponding BinaryElementView, sets its index,
+ * size, and location, and adds it to the list of element views to be displayed.
+ *
+ * @param board The BinaryBoard representing the current state of the binary puzzle
+ */
public BinaryView(BinaryBoard board) {
super(new BoardController(), new BinaryController(), board.getDimension());
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java
deleted file mode 100644
index 8b1378917..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/BlankTile.java
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java
index 8b1378917..dc3d75e00 100644
--- a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java
@@ -1 +1,13 @@
+package edu.rpi.legup.puzzle.binary.elements;
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class NumberTile extends PlaceableElement {
+ public NumberTile() {
+ super(
+ "BINA-ELEM-0001",
+ "Number Tile",
+ "A number tile",
+ "edu/rpi/legup/images/binary/tiles/NumberTile.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java
new file mode 100644
index 000000000..e32a2d12f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java
@@ -0,0 +1,13 @@
+package edu.rpi.legup.puzzle.binary.elements;
+
+import edu.rpi.legup.model.elements.PlaceableElement;
+
+public class UnknownTile extends PlaceableElement {
+ public UnknownTile() {
+ super(
+ "BINA-ELEM-0002",
+ "Unknown Tile",
+ "A blank tile",
+ "edu/rpi/legup/images/binary/tiles/UnknownTile.png");
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt
new file mode 100644
index 000000000..54db0ee0b
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt
@@ -0,0 +1,2 @@
+BINA-ELEM-0001 : NumberTile
+BINA-ELEM-0002 : UnknownTile
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java
index e38c6b78d..6ced37a9c 100644
--- a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java
@@ -14,8 +14,9 @@ public class CompleteRowColumnDirectRule extends DirectRule {
public CompleteRowColumnDirectRule() {
super(
"BINA-BASC-0003",
- "Complete Row Column",
- "If a row/column of length n contains n/2 of a single value, the remaining cells must contain the other value",
+ "Complete Row/Column",
+ "If a row/column of length n contains n/2 of a single value, the remaining "
+ + "cells must contain the other value",
"edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png");
}
@@ -31,23 +32,27 @@ public CompleteRowColumnDirectRule() {
@Override
public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard();
- ContradictionRule contraRule = new UnbalancedRowOrColumnContradictionRule();
+ ContradictionRule contraRule = new UnbalancedRowColumnContradictionRule();
BinaryCell binaryCell = (BinaryCell) puzzleElement;
BinaryBoard modified = origBoard.copy();
- BinaryCell c = (BinaryCell) modified.getPuzzleElement(puzzleElement);
- // System.out.println("ORIG" + binaryCell.getData());
- // System.out.println("AFTER" + Math.abs(binaryCell.getData() - 1));
- modified.getPuzzleElement(puzzleElement).setData(binaryCell.getData());
- System.out.println(contraRule.checkContradictionAt(modified, puzzleElement));
-
- if (contraRule.checkContradictionAt(modified, puzzleElement) != null) {
+ // Flip the cell and check to see if there will be an unbalanced row/column contradiction,
+ // if so the rule is applied correctly
+ modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1));
+ if (contraRule.checkContradictionAt(modified, puzzleElement) == null) {
return null;
}
- return "Grouping of Three Ones or Zeros not found";
+ return "Unbalanced row/column found";
}
+ /**
+ * Creates a transition {@link Board} that has this rule applied to it using the {@link
+ * TreeNode}.
+ *
+ * @param node tree node used to create default transition board
+ * @return default board or null if this rule cannot be applied to this tree node
+ */
@Override
public Board getDefaultBoard(TreeNode node) {
return null;
diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java
new file mode 100644
index 000000000..df84dd540
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java
@@ -0,0 +1,204 @@
+// package edu.rpi.legup.puzzle.binary.rules;
+//
+// import edu.rpi.legup.model.gameboard.Board;
+// import edu.rpi.legup.model.gameboard.PuzzleElement;
+// import edu.rpi.legup.model.rules.DirectRule;
+// import edu.rpi.legup.model.tree.TreeNode;
+// import edu.rpi.legup.model.tree.TreeTransition;
+// import edu.rpi.legup.puzzle.binary.BinaryBoard;
+// import edu.rpi.legup.puzzle.binary.BinaryCell;
+// import edu.rpi.legup.puzzle.binary.BinaryType;
+//
+// import java.util.LinkedList;
+// import java.util.Queue;
+// import java.lang.Math.*;
+// import java.lang.reflect.Array;
+// import java.util.ArrayList;
+//
+// public class EliminateTheImpossibleDirectRule extends DirectRule {
+// private final String INVALID_USE_MESSAGE = "Number at cell is incorrect";
+//
+// public EliminateTheImpossibleDirectRule() {
+// super(
+// "BINA-BASC-0004",
+// "Eliminate The Impossible",
+// "Out of the remaining empty cells in this row or column, this digit must go here,
+// otherwise there will be a future contradiction",
+// "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png");
+// }
+//
+// // Function to generate all binary strings
+// void generatePossibilitites(int spots, ArrayList 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,14 @@ 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 +555,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 +576,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.isEmpty()) {
+ legupUI.displayPanel(1);
+ }
if (puzzleFile != null && puzzleFile.exists()) {
try {
legupUI.displayPanel(1);
@@ -554,7 +623,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 +647,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 +689,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 +721,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 +745,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 +772,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 +820,193 @@ 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;
- }
+ /**
+ * 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);
+ }
- toolBar = new JToolBar();
- toolBar.setFloatable(false);
- toolBar.setRollover(true);
+ /**
+ * 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:
+ *
+ *
+ *
+ */
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..75761c475 100644
--- a/src/main/java/edu/rpi/legup/ui/HomePanel.java
+++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java
@@ -25,6 +25,11 @@
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 +41,35 @@ 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);
+ legupUI.getProofEditor().loadPuzzle("", null);
}
};
- 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);
- }
- };
-
- 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 +98,33 @@ 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 +142,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 +156,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 +180,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 +264,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 +473,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 +498,12 @@ 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 +511,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 +524,29 @@ 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 +590,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 +650,46 @@ 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.isEmpty()) {
+ 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");
+ }
- // Set game type on the puzzle editor
- this.legupUI.displayPanel(2);
- this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns);
+ 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);
+ }
}
/**
- * 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..639f21211 100644
--- a/src/main/java/edu/rpi/legup/ui/LegupPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/LegupPanel.java
@@ -2,9 +2,15 @@
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..75f822a6c 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,24 @@ 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 +127,29 @@ 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 +162,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 +178,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 +200,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..3b66931a7 100644
--- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java
+++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java
@@ -15,6 +15,10 @@
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 +110,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 +136,30 @@ 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..e90d06640 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,14 @@ 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 +423,13 @@ 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 +443,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..5ecbd5564 100644
--- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java
@@ -36,6 +36,13 @@
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 +53,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 +74,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 +89,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 +118,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 +133,46 @@ 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:
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+ 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());
- 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();
+ 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();
+ });
- toolBar.add(getToolBarButtons()[i]);
- getToolBarButtons()[i].setToolTipText(toolBarName);
+ getToolBar2Buttons()[2] = redo;
+ toolBar2.add(getToolBar2Buttons()[2]);
- getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM);
- getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER);
- }
+ 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);
+ }
- // 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 toolbar1 buttons
+ *
+ * @param toolBar1Buttons toolbar buttons
+ */
+ public void setToolBar1Buttons(JButton[] toolBar1Buttons) {
+ this.toolBar1Buttons = toolBar1Buttons;
+ }
+
+ /**
+ * 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,11 +1033,61 @@ 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();
@@ -885,16 +1111,19 @@ 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 +1178,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 +1241,35 @@ 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,23 +1277,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);
- }
+ public void onClearHistory() {}
/**
* Called when an action is redone
@@ -1051,9 +1300,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 +1321,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 +1365,7 @@ 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..7c2ba06ff 100644
--- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java
+++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java
@@ -28,18 +28,25 @@
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 +58,20 @@ 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 +80,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 +115,10 @@ 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,26 +130,31 @@ 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");
@@ -134,9 +166,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 +179,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 +190,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 +265,11 @@ 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 +278,192 @@ 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/Check.png");
- ImageIcon imageIcon = new ImageIcon(check_and_save);
- Image image = imageIcon.getImage();
- imageIcon =
+ .getResource("edu/rpi/legup/images/Legup/Open.png");
+ ImageIcon OpenImageIcon = new ImageIcon(open_url);
+ Image OpenImage = OpenImageIcon.getImage();
+ OpenImageIcon =
new ImageIcon(
- image.getScaledInstance(
+ OpenImage.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(
- 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());
+ 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()));
+ }
}
});
- getToolBarButtons()[lastone + 1] = checkandsave;
- System.out.println("it is create new file");
- toolBar = new JToolBar();
- toolBar.setFloatable(false);
- toolBar.setRollover(true);
+ getToolBar2Buttons()[0] = resetButton;
+ toolBar2.add(getToolBar2Buttons()[0]);
- 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();
+ 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));
- toolBar.add(getToolBarButtons()[i]);
- getToolBarButtons()[i].setToolTipText(toolBarName);
+ JButton saveas = new JButton("Save As", SaveAsImageIcon);
+ saveas.setFocusPainted(false);
+ saveas.addActionListener((ActionEvent) -> savePuzzle());
- getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM);
- getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER);
- }
+ getToolBar2Buttons()[1] = saveas;
+ toolBar2.add(getToolBar2Buttons()[1]);
+
+ URL save_and_solve =
+ ClassLoader.getSystemClassLoader()
+ .getResource("edu/rpi/legup/images/Legup/Check.png");
+ ImageIcon SaveSolveImageIcon = new ImageIcon(save_and_solve);
+ Image SaveSolveImage = SaveSolveImageIcon.getImage();
+ SaveSolveImageIcon =
+ new ImageIcon(
+ SaveSolveImage.getScaledInstance(
+ this.TOOLBAR_ICON_SCALE,
+ this.TOOLBAR_ICON_SCALE,
+ Image.SCALE_SMOOTH));
+
+ JButton saveandsolve = new JButton("Save & Solve", SaveSolveImageIcon);
+ saveandsolve.setFocusPainted(false);
+ saveandsolve.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ 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());
+ }
+ }
+ });
+ getToolBar2Buttons()[2] = saveandsolve;
+ toolBar2.add(getToolBar2Buttons()[2]);
- // 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 +477,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 +496,18 @@ 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 +531,6 @@ public Object[] promptPuzzle() {
fileBrowser.setAcceptAllFileFilterUsed(false);
File puzzlePath = fileBrowser.getSelectedFile();
- System.out.println(puzzlePath.getAbsolutePath());
if (puzzlePath != null) {
fileName = puzzlePath.getAbsolutePath();
@@ -420,6 +545,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 +561,13 @@ 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 +575,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 +591,90 @@ 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);
- }
+ public void onClearHistory() {}
+ /**
+ * 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 +690,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 +717,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 +760,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 +775,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..589573154 100644
--- a/src/main/java/edu/rpi/legup/ui/ScrollView.java
+++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java
@@ -6,6 +6,11 @@
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 +170,12 @@ 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 +293,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..622d16d8d 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..40f36113f 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,13 @@ 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 +52,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..18b47d98b 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,7 @@ public void setBoard(Board board) {
}
}
+ /** Configures the view to handle case interactions */
protected void setCasePickable() {
CaseBoard caseBoard = (CaseBoard) board;
Board baseBoard = caseBoard.getBaseBoard();
@@ -183,6 +188,11 @@ public ArrayList