/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package lpa.gui;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SpinnerNumberModel;
import lpa.command.Command;
import lpa.command.CompoundCommand;
import lpa.command.EdgeCommand;
import lpa.model.*;
/**
* Main frame class with all the GUI.
*
* @author Dimitriy Leonov
*/
public class MainFrame extends javax.swing.JFrame {
private Grid grid;
private final Stack<Command> undoStack = new Stack<>();
private final Stack<Command> redoStack = new Stack<>();
private boolean apply_strategies = false;
private GridElement currentHighlightedElement = null;
/**
* Creates new form MainFrame
*/
public MainFrame() {
initComponents();
textArea.setLineWrap(true);
editModeMenuItem.setSelected(false);
applyStrategiesMenuItem.setSelected(false);
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
quickOpenMenuItem.setVisible(false); //hide debug menu item
setLocationRelativeTo(null);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
newGridDialog = new javax.swing.JDialog();
okButton = new javax.swing.JButton();
widthSpinner = new javax.swing.JSpinner(new SpinnerNumberModel(0, 0, 30, 1));
heightSpinner = new javax.swing.JSpinner(new SpinnerNumberModel(0, 0, 30, 1));
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
textArea = new javax.swing.JTextArea();
puzzlePanel = new javax.swing.JPanel() {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (grid == null) {
return;
}
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
if (apply_strategies) {
CompoundCommand c = grid.applyStrategies();
if (!undoStack.isEmpty()) {
Command last_edge_action = undoStack.pop();
last_edge_action.undo();
c.add(last_edge_action);
}
c.execute();
undoStack.add(c);
}
textArea.setText(grid.toString());
errorLabel.setText(grid.checkGrid());
List<GridElement> items = grid.getGridElements();
for (GridElement i : items) {
i.draw(g, this.getSize());
}
}
};
errorLabel = new javax.swing.JLabel();
jButton2 = new javax.swing.JButton();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenuItem3 = new javax.swing.JMenuItem();
jMenuItem1 = new javax.swing.JMenuItem();
jMenuItem6 = new javax.swing.JMenuItem();
jMenuItem2 = new javax.swing.JMenuItem();
quickOpenMenuItem = new javax.swing.JMenuItem();
jMenu2 = new javax.swing.JMenu();
jMenuItem4 = new javax.swing.JMenuItem();
jMenuItem5 = new javax.swing.JMenuItem();
editModeMenuItem = new javax.swing.JCheckBoxMenuItem();
applyStrategiesMenuItem = new javax.swing.JCheckBoxMenuItem();
newGridDialog.setName("newGridDialog"); // NOI18N
newGridDialog.setResizable(false);
okButton.setText("OK");
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okDialogAction(evt);
}
});
widthSpinner.setEditor(new javax.swing.JSpinner.NumberEditor(widthSpinner, ""));
widthSpinner.setValue(5);
heightSpinner.setEditor(new javax.swing.JSpinner.NumberEditor(heightSpinner, ""));
heightSpinner.setValue(5);
jLabel1.setText("Width");
jLabel2.setText("Height");
javax.swing.GroupLayout newGridDialogLayout = new javax.swing.GroupLayout(newGridDialog.getContentPane());
newGridDialog.getContentPane().setLayout(newGridDialogLayout);
newGridDialogLayout.setHorizontalGroup(
newGridDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newGridDialogLayout.createSequentialGroup()
.addContainerGap()
.addGroup(newGridDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(okButton)
.addGroup(newGridDialogLayout.createSequentialGroup()
.addComponent(jLabel2)
.addGap(18, 18, 18)
.addComponent(heightSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, newGridDialogLayout.createSequentialGroup()
.addComponent(jLabel1)
.addGap(23, 23, 23)
.addComponent(widthSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
newGridDialogLayout.setVerticalGroup(
newGridDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newGridDialogLayout.createSequentialGroup()
.addGap(14, 14, 14)
.addGroup(newGridDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(widthSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1))
.addGap(18, 18, 18)
.addGroup(newGridDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2)
.addComponent(heightSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(okButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Loop Puzzle Assistant");
setAutoRequestFocus(false);
setBackground(new java.awt.Color(255, 255, 255));
setForeground(java.awt.Color.white);
textArea.setEditable(false);
textArea.setColumns(20);
textArea.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
textArea.setRows(5);
textArea.setAutoscrolls(false);
textArea.setRequestFocusEnabled(false);
jScrollPane1.setViewportView(textArea);
puzzlePanel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
puzzlePanelMousePressed(evt);
}
});
puzzlePanel.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(java.awt.event.MouseEvent evt) {
mouseMoveAction(evt);
}
});
javax.swing.GroupLayout puzzlePanelLayout = new javax.swing.GroupLayout(puzzlePanel);
puzzlePanel.setLayout(puzzlePanelLayout);
puzzlePanelLayout.setHorizontalGroup(
puzzlePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(puzzlePanelLayout.createSequentialGroup()
.addComponent(errorLabel)
.addGap(0, 514, Short.MAX_VALUE))
);
puzzlePanelLayout.setVerticalGroup(
puzzlePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, puzzlePanelLayout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(errorLabel))
);
jButton2.setText("Reset");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
resetAction(evt);
}
});
jMenu1.setText("File");
jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem3.setText("New...");
jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newAction(evt);
}
});
jMenu1.add(jMenuItem3);
jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem1.setText("Open...");
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openFile(evt);
}
});
jMenu1.add(jMenuItem1);
jMenuItem6.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem6.setText("Save...");
jMenuItem6.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveAction(evt);
}
});
jMenu1.add(jMenuItem6);
jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem2.setText("Quit");
jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
quitAction(evt);
}
});
jMenu1.add(jMenuItem2);
quickOpenMenuItem.setText("QuickOpen");
quickOpenMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
quickOpenAction(evt);
}
});
jMenu1.add(quickOpenMenuItem);
jMenuBar1.add(jMenu1);
jMenu2.setText("Edit");
jMenuItem4.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem4.setText("Undo");
jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
undoAction(evt);
}
});
jMenu2.add(jMenuItem4);
jMenuItem5.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK));
jMenuItem5.setText("Redo");
jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
redoAction(evt);
}
});
jMenu2.add(jMenuItem5);
editModeMenuItem.setSelected(true);
editModeMenuItem.setText("Edit Mode");
editModeMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editModeMenuItemAction(evt);
}
});
jMenu2.add(editModeMenuItem);
applyStrategiesMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, java.awt.event.InputEvent.CTRL_MASK));
applyStrategiesMenuItem.setSelected(true);
applyStrategiesMenuItem.setText("Apply Strategies");
applyStrategiesMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
applyStrategiesAction(evt);
}
});
jMenu2.add(applyStrategiesMenuItem);
jMenuBar1.add(jMenu2);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jButton2)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(puzzlePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(puzzlePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jButton2)
.addGap(9, 9, 9))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void quitAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_quitAction
System.exit(0);
}//GEN-LAST:event_quitAction
private void openFile(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFile
JFileChooser fc = new JFileChooser(".");
fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
@Override
public boolean accept(File f) {
return f.isFile() && f.getName().toLowerCase().endsWith(".txt");
}
@Override
public String getDescription() {
return "LoopPuzzle files (*.txt)";
}
});
int result = fc.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
try {
Scanner scn = new Scanner(file);
grid = new Grid(scn);
puzzlePanel.repaint();
} catch (IOException ex) {
System.out.println("Problem accessing file" + file.getAbsolutePath());
}
} else {
System.out.println("File access cancelled by user.");
}
}//GEN-LAST:event_openFile
// Allows to open predefined file test.txt. This is for debug purposes only.
private void quickOpenAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_quickOpenAction
try {
File file = new File("test.txt");
Scanner scn = new Scanner(file);
grid = new Grid(scn);
puzzlePanel.repaint();
} catch (IOException ex) {
System.out.println("Cannot read file test.txt.");
}
}//GEN-LAST:event_quickOpenAction
private void puzzlePanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_puzzlePanelMousePressed
if (grid == null) {
return;
}
GridElement selectedElement = grid.getElementByPoint(evt.getPoint(), puzzlePanel.getSize());
if (selectedElement != null) {
if (selectedElement instanceof Edge) {
undoStack.push(new EdgeCommand((Edge) selectedElement));
undoStack.peek().execute();
}
if (grid.editMode() && selectedElement instanceof Cell) {
((Cell) selectedElement).setNextValue();
}
if (!(selectedElement instanceof Cell)) {
puzzlePanel.repaint();
}
}
}//GEN-LAST:event_puzzlePanelMousePressed
private void resetAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetAction
while (!undoStack.empty()) {
undoStack.pop().undo();
}
redoStack.clear();
puzzlePanel.repaint();
}//GEN-LAST:event_resetAction
private void undoAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_undoAction
if (undoStack.empty()) {
return;
}
redoStack.push(undoStack.pop());
redoStack.peek().undo();
puzzlePanel.repaint();
}//GEN-LAST:event_undoAction
private void redoAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redoAction
if (redoStack.empty()) {
return;
}
undoStack.push(redoStack.pop());
undoStack.peek().execute();
puzzlePanel.repaint();
}//GEN-LAST:event_redoAction
private void saveAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAction
if (grid == null) {
return;
}
JFileChooser fc = new JFileChooser(".") {
@Override
public void approveSelection() {
File f = getSelectedFile();
if (f.exists() && getDialogType() == SAVE_DIALOG) {
int result = JOptionPane.showConfirmDialog(this, "The file exists, overwrite?", "Existing file", JOptionPane.YES_NO_CANCEL_OPTION);
switch (result) {
case JOptionPane.YES_OPTION:
super.approveSelection();
return;
case JOptionPane.NO_OPTION:
return;
case JOptionPane.CLOSED_OPTION:
return;
case JOptionPane.CANCEL_OPTION:
cancelSelection();
}
}
super.approveSelection();
}
};
fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
@Override
public boolean accept(File f) {
return f.isFile() && f.getName().toLowerCase().endsWith(".txt");
}
@Override
public String getDescription() {
return "LoopPuzzle files (*.txt)";
}
});
int result = fc.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
try (BufferedWriter file = new BufferedWriter(
new FileWriter(fc.getSelectedFile()
+ (fc.getSelectedFile().getName().toLowerCase().endsWith(".txt") ? "" : ".txt")))) {
file.write(textArea.getText());
file.close();
} catch (IOException ex) {
System.out.println("problem accessing file" + fc.getSelectedFile());
}
} else {
System.out.println("File access cancelled by user.");
}
}//GEN-LAST:event_saveAction
private void editModeMenuItemAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editModeMenuItemAction
if (grid == null) {
return;
}
grid.setEditMode(!grid.editMode());
}//GEN-LAST:event_editModeMenuItemAction
private void applyStrategiesAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyStrategiesAction
apply_strategies = !apply_strategies;
puzzlePanel.repaint();
}//GEN-LAST:event_applyStrategiesAction
private void mouseMoveAction(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mouseMoveAction
if (grid == null) {
return;
}
boolean update = false;
if (currentHighlightedElement != null) {
currentHighlightedElement.setHighlighted(false);
update = true;
}
currentHighlightedElement = grid.getElementByPoint(evt.getPoint(), puzzlePanel.getSize());
if (currentHighlightedElement != null) {
currentHighlightedElement.setHighlighted(true);
update = true;
}
if (update) {
puzzlePanel.repaint();
}
}//GEN-LAST:event_mouseMoveAction
private void newAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newAction
newGridDialog.setVisible(true);
newGridDialog.setSize(140, 180);
newGridDialog.setLocationRelativeTo(null);
}//GEN-LAST:event_newAction
private void okDialogAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okDialogAction
newGridDialog.setVisible(false);
grid = new Grid((int)widthSpinner.getValue(), (int)heightSpinner.getValue());
puzzlePanel.repaint();
}//GEN-LAST:event_okDialogAction
/**
* Program entry point.
*
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new MainFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBoxMenuItem applyStrategiesMenuItem;
private javax.swing.JCheckBoxMenuItem editModeMenuItem;
private javax.swing.JLabel errorLabel;
private javax.swing.JSpinner heightSpinner;
private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JMenu jMenu1;
private javax.swing.JMenu jMenu2;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem jMenuItem1;
private javax.swing.JMenuItem jMenuItem2;
private javax.swing.JMenuItem jMenuItem3;
private javax.swing.JMenuItem jMenuItem4;
private javax.swing.JMenuItem jMenuItem5;
private javax.swing.JMenuItem jMenuItem6;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JDialog newGridDialog;
private javax.swing.JButton okButton;
private javax.swing.JPanel puzzlePanel;
private javax.swing.JMenuItem quickOpenMenuItem;
private javax.swing.JTextArea textArea;
private javax.swing.JSpinner widthSpinner;
// End of variables declaration//GEN-END:variables
}