universe@3: /* universe@3: * Copyright 2013 Mike Becker. All rights reserved. universe@10: * universe@3: * Redistribution and use in source and binary forms, with or without universe@3: * modification, are permitted provided that the following conditions are met: universe@10: * universe@3: * 1. Redistributions of source code must retain the above copyright universe@3: * notice, this list of conditions and the following disclaimer. universe@10: * universe@3: * 2. Redistributions in binary form must reproduce the above copyright universe@3: * notice, this list of conditions and the following disclaimer in the universe@3: * documentation and/or other materials provided with the distribution. universe@10: * universe@3: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@3: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@3: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@3: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@3: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@3: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@3: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@3: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@3: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@3: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@3: * POSSIBILITY OF SUCH DAMAGE. universe@3: */ universe@3: universe@2: package de.uapcore.sudoku; universe@2: universe@9: import javax.swing.*; universe@2: import java.awt.event.ActionEvent; universe@2: import java.awt.event.ActionListener; universe@6: import java.io.File; universe@6: import java.io.IOException; universe@2: universe@2: /** universe@10: * Handles all user issued actions in the application. universe@2: */ universe@2: public final class ActionHandler implements ActionListener { universe@10: universe@2: public static final String SAVE = "save"; universe@2: public static final String CHECK = "check"; universe@2: public static final String SOLVE = "solve"; universe@10: universe@3: public static final String NEW = "new"; universe@3: public static final String OPEN = "open"; universe@3: public static final String SAVE_AS = "save as"; universe@3: public static final String QUIT = "quit"; universe@3: public static final String ABOUT = "about"; universe@10: universe@12: private final Field field; universe@12: private final Solver solver; universe@12: private final DocumentHandler doc; universe@10: universe@10: /** universe@10: * Constructs a new action handler instance. universe@10: * universe@10: * @param f a reference to the playing field universe@10: */ universe@2: public ActionHandler(Field f) { universe@2: field = f; universe@2: solver = new Solver(); universe@5: doc = new DocumentHandler(); universe@5: } universe@10: universe@10: /** universe@10: * Prompts the user for a file name. universe@10: *

universe@10: * If the user chooses an existing file, they are asked whether the file should be overwritten. universe@10: * universe@10: * @return true if the user approves a chosen file name universe@10: */ universe@5: private boolean chooseSaveFilename() { universe@6: JFileChooser fc = new JFileChooser("."); universe@6: fc.setMultiSelectionEnabled(false); universe@6: if (fc.showSaveDialog(field) == JFileChooser.APPROVE_OPTION) { universe@6: File f = fc.getSelectedFile(); universe@6: if (f.exists()) { universe@6: int result = JOptionPane.showConfirmDialog(field, universe@6: "Bereits existierende Datei überschreiben?", "Sudoku", universe@6: JOptionPane.YES_NO_OPTION); universe@6: if (result == JOptionPane.YES_OPTION) { universe@6: doc.setFilename(f.getAbsolutePath()); universe@6: return true; universe@6: } else { universe@6: return false; universe@6: } universe@6: } else { universe@6: doc.setFilename(f.getAbsolutePath()); universe@6: return true; universe@6: } universe@6: } else { universe@6: return false; universe@6: } universe@2: } universe@10: universe@10: /** universe@10: * Prompts the user for a file to open and, if approved, loads that file. universe@10: */ universe@6: private void open() { universe@6: JFileChooser fc = new JFileChooser("."); universe@6: fc.setMultiSelectionEnabled(false); universe@6: if (fc.showOpenDialog(field) == JFileChooser.APPROVE_OPTION) { universe@6: File f = fc.getSelectedFile(); universe@6: doc.setFilename(f.getAbsolutePath()); universe@6: try { universe@6: doc.load(field); universe@6: } catch (IOException e) { universe@6: JOptionPane.showMessageDialog(field, universe@10: "Datei konnte nicht geladen werden: " + e.getMessage(), universe@10: "Sudoku", JOptionPane.ERROR_MESSAGE); universe@6: } universe@6: } universe@6: } universe@10: universe@10: /** universe@10: * Attempts to save the Sudoku field to a file. universe@10: *

universe@10: * If necessary, the user is prompted for a file name. universe@10: *

universe@10: * The field must be solvable, otherwise it cannot be saved. universe@10: * universe@10: * @param rename true if the user shall always be prompted, even if a file name is already known universe@10: * @return true if the user approves the chosen file name universe@10: */ universe@6: private boolean save(boolean rename) { universe@6: if (!doc.isFilenameSet() || rename) { universe@5: if (!chooseSaveFilename()) { universe@5: return false; universe@5: } universe@5: } universe@2: if (solver.check(field)) { universe@6: try { universe@6: doc.save(field); universe@6: } catch (IOException e) { universe@6: JOptionPane.showMessageDialog(field, universe@10: "Datei konnte nicht gespeichert werden: " + e.getMessage(), universe@10: "Sudoku", JOptionPane.ERROR_MESSAGE); universe@6: } universe@3: return true; universe@2: } else { universe@2: JOptionPane.showMessageDialog(field, universe@2: "Das Feld kann mit Fehlern nicht gespeichert werden!", universe@2: "Sudoku", JOptionPane.ERROR_MESSAGE); universe@3: return false; universe@2: } universe@2: } universe@10: universe@10: /** universe@10: * Checks the Sudoku field and displays the result as a dialog box. universe@10: */ universe@2: private void check() { universe@2: if (solver.check(field)) { universe@2: JOptionPane.showMessageDialog(field, "Überprüfung erfolgreich!", universe@2: "Sudoku", JOptionPane.INFORMATION_MESSAGE); universe@2: } else { universe@2: JOptionPane.showMessageDialog(field, "Das Feld enthält Fehler!", universe@2: "Sudoku", JOptionPane.WARNING_MESSAGE); universe@2: } universe@2: } universe@10: universe@10: /** universe@10: * Solves the field or displays an error dialog if the field is not solvable. universe@10: */ universe@2: private void solve() { universe@7: if (!solver.check(field) || !solver.solve(field)) { universe@7: JOptionPane.showMessageDialog(field, "Das Feld ist nicht lösbar!", universe@7: "Sudoku", JOptionPane.WARNING_MESSAGE); universe@7: } universe@2: } universe@10: universe@10: /** universe@10: * Checks whether there are unsaved changes and asks the user to save the field. universe@10: * universe@10: * @return true if there are no unsaved changes or the user actively decides to continue - false, otherwise universe@10: */ universe@4: private boolean saveUnsaved() { universe@4: boolean proceed = false; universe@4: if (field.isAnyCellModified()) { universe@4: int result = JOptionPane.showConfirmDialog(field, universe@4: "Das Feld ist ungespeichert - jetzt speichern?", universe@4: "Sudoku", JOptionPane.YES_NO_CANCEL_OPTION); universe@4: if (result == JOptionPane.YES_OPTION) { universe@6: if (save(false)) { universe@4: proceed = true; universe@4: } universe@4: } else if (result == JOptionPane.NO_OPTION) { universe@4: proceed = true; universe@4: } universe@4: } else { universe@4: proceed = true; universe@4: } universe@10: universe@4: return proceed; universe@4: } universe@2: universe@2: @Override universe@2: public void actionPerformed(ActionEvent e) { universe@2: switch (e.getActionCommand()) { universe@10: case NEW: universe@10: if (saveUnsaved()) { universe@10: doc.clearFilename(); universe@10: field.clear(); universe@10: } universe@10: break; universe@10: case OPEN: universe@10: open(); universe@10: break; universe@10: case SAVE: universe@10: save(false); universe@10: break; universe@10: case SAVE_AS: universe@10: save(true); universe@10: break; universe@10: case CHECK: universe@10: check(); universe@10: break; universe@10: case SOLVE: universe@10: solve(); universe@10: break; universe@10: case QUIT: universe@10: if (saveUnsaved()) { universe@10: System.exit(0); universe@10: } universe@10: break; universe@10: case ABOUT: universe@10: JOptionPane.showMessageDialog(field, universe@10: "Sudoku - Copyright (c) 2013 Mike Becker\nwww.uap-core.de" + universe@10: "\nPublished under the BSD License", universe@10: "Sudoku", JOptionPane.INFORMATION_MESSAGE); universe@10: break; universe@10: default: universe@10: throw new UnsupportedOperationException( universe@10: "unknown action: " + e.getActionCommand()); universe@2: } universe@2: } universe@10: universe@2: }