1 | /* |
2 | * Copyright (c) 2005 The PseudoQ Project. |
3 | * |
4 | * This file is part of PseudoQ. |
5 | * |
6 | * PseudoQ is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU Lesser General Public License as published by |
8 | * the Free Software Foundation; either version 2.1 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * PseudoQ is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public License |
17 | * along with PseudoQ; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ |
20 | |
21 | package net.sourceforge.pseudoq.gui; |
22 | |
23 | import java.awt.event.ItemEvent; |
24 | import java.awt.print.PageFormat; |
25 | import java.awt.print.PrinterException; |
26 | import java.awt.print.PrinterJob; |
27 | import java.io.File; |
28 | import javax.swing.JFileChooser; |
29 | import javax.swing.JOptionPane; |
30 | import javax.swing.JToggleButton; |
31 | |
32 | import net.sourceforge.pseudoq.model.Coordinate; |
33 | import net.sourceforge.pseudoq.model.Grid; |
34 | import net.sourceforge.pseudoq.model.Puzzle; |
35 | import net.sourceforge.pseudoq.model.PuzzleFactory; |
36 | import net.sourceforge.pseudoq.model.io.PuzzleFileReader; |
37 | import net.sourceforge.pseudoq.model.io.PuzzleFileWriter; |
38 | import net.sourceforge.pseudoq.solver.Solution; |
39 | import net.sourceforge.pseudoq.solver.SolutionStep; |
40 | import net.sourceforge.pseudoq.solver.Solver; |
41 | import net.sourceforge.pseudoq.solver.SolverFactory; |
42 | import net.sourceforge.pseudoq.solver.UnsolveablePuzzleException; |
43 | |
44 | /** |
45 | * Puzzle interface Frame window. |
46 | * @author <a href="http://sourceforge.net/users/stevensa">Andrew Stevens</a> |
47 | */ |
48 | public class PuzzleFrame extends javax.swing.JFrame { |
49 | /** Log4J logger */ |
50 | private static final org.apache.log4j.Logger log = |
51 | org.apache.log4j.LogManager.getLogger(PuzzleFrame.class); |
52 | |
53 | private enum ModeEnum { DESIGN, PLAY }; |
54 | |
55 | /** Creates new form PuzzleFrame */ |
56 | public PuzzleFrame(Puzzle puzzle) { |
57 | setPuzzle(puzzle); |
58 | initComponents(); |
59 | if (puzzle.isPlayed()) { |
60 | switchToMode(ModeEnum.PLAY); |
61 | playModeRadioButton.setSelected(true); |
62 | } |
63 | if (puzzle.isSolved() && !puzzle.isComplete()) { |
64 | showSolutionCheckBox.setEnabled(true); |
65 | } |
66 | } |
67 | |
68 | /** This method is called from within the constructor to |
69 | * initialize the form. |
70 | * WARNING: Do NOT modify this code. The content of this method is |
71 | * always regenerated by the Form Editor. |
72 | */ |
73 | // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents |
74 | private void initComponents() { |
75 | buttonGroup1 = new javax.swing.ButtonGroup(); |
76 | buttonGroup2 = new javax.swing.ButtonGroup(); |
77 | jPanel1 = new javax.swing.JPanel(); |
78 | designModeRadioButton = new javax.swing.JRadioButton(); |
79 | playModeRadioButton = new javax.swing.JRadioButton(); |
80 | showSolutionCheckBox = new javax.swing.JCheckBox(); |
81 | puzzlePanel = new net.sourceforge.pseudoq.gui.PuzzlePanel(); |
82 | digitButtonPanel = new javax.swing.JPanel(); |
83 | digitButtons = new JToggleButton[puzzle.getMaxInt() + 1]; |
84 | jPanel2 = new javax.swing.JPanel(); |
85 | resetButton = new javax.swing.JButton(); |
86 | solveButton = new javax.swing.JButton(); |
87 | hintButton = new javax.swing.JButton(); |
88 | menuBar = new javax.swing.JMenuBar(); |
89 | fileMenu = new javax.swing.JMenu(); |
90 | newMenuItem = new javax.swing.JMenuItem(); |
91 | openMenuItem = new javax.swing.JMenuItem(); |
92 | saveMenuItem = new javax.swing.JMenuItem(); |
93 | saveAsMenuItem = new javax.swing.JMenuItem(); |
94 | jSeparator1 = new javax.swing.JSeparator(); |
95 | pageSetupMenuItem = new javax.swing.JMenuItem(); |
96 | printMenuItem = new javax.swing.JMenuItem(); |
97 | jSeparator2 = new javax.swing.JSeparator(); |
98 | closeMenuItem = new javax.swing.JMenuItem(); |
99 | editMenu = new javax.swing.JMenu(); |
100 | undoMenuItem = new javax.swing.JMenuItem(); |
101 | redoMenuItem = new javax.swing.JMenuItem(); |
102 | helpMenu = new javax.swing.JMenu(); |
103 | contentsMenuItem = new javax.swing.JMenuItem(); |
104 | aboutMenuItem = new javax.swing.JMenuItem(); |
105 | |
106 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); |
107 | setTitle("PseudoQ - " + (puzzle.getFilename() != null ? removePath(puzzle.getFilename()) : "<new>")); |
108 | buttonGroup1.add(designModeRadioButton); |
109 | designModeRadioButton.setMnemonic('d'); |
110 | designModeRadioButton.setSelected(true); |
111 | designModeRadioButton.setText("Design"); |
112 | designModeRadioButton.addActionListener(new java.awt.event.ActionListener() { |
113 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
114 | designModeRadioButtonActionPerformed(evt); |
115 | } |
116 | }); |
117 | |
118 | jPanel1.add(designModeRadioButton); |
119 | |
120 | buttonGroup1.add(playModeRadioButton); |
121 | playModeRadioButton.setMnemonic('p'); |
122 | playModeRadioButton.setText("Play"); |
123 | playModeRadioButton.addActionListener(new java.awt.event.ActionListener() { |
124 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
125 | playModeRadioButtonActionPerformed(evt); |
126 | } |
127 | }); |
128 | |
129 | jPanel1.add(playModeRadioButton); |
130 | |
131 | showSolutionCheckBox.setMnemonic('w'); |
132 | showSolutionCheckBox.setText("Show solution"); |
133 | showSolutionCheckBox.setEnabled(puzzle.isSolved()); |
134 | showSolutionCheckBox.addItemListener(new java.awt.event.ItemListener() { |
135 | public void itemStateChanged(java.awt.event.ItemEvent evt) { |
136 | showSolutionCheckBoxItemStateChanged(evt); |
137 | } |
138 | }); |
139 | |
140 | jPanel1.add(showSolutionCheckBox); |
141 | |
142 | getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH); |
143 | |
144 | puzzlePanel.setLayout(null); |
145 | |
146 | puzzlePanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(50, 50, 50, 50)); |
147 | puzzlePanel.setPuzzle(this.getPuzzle()); |
148 | puzzlePanel.addPropertyChangeListener(new java.beans.PropertyChangeListener() { |
149 | public void propertyChange(java.beans.PropertyChangeEvent evt) { |
150 | puzzlePanelPropertyChange(evt); |
151 | } |
152 | }); |
153 | |
154 | getContentPane().add(puzzlePanel, java.awt.BorderLayout.CENTER); |
155 | |
156 | digitButtonPanel.setLayout(new java.awt.GridLayout(0, 1)); |
157 | |
158 | for (int i = 0; i <= puzzle.getMaxInt(); i++) { |
159 | createDigitButton(i); |
160 | } |
161 | getContentPane().add(digitButtonPanel, java.awt.BorderLayout.EAST); |
162 | |
163 | resetButton.setMnemonic('r'); |
164 | resetButton.setText("Reset"); |
165 | resetButton.addActionListener(new java.awt.event.ActionListener() { |
166 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
167 | resetButtonActionPerformed(evt); |
168 | } |
169 | }); |
170 | |
171 | jPanel2.add(resetButton); |
172 | |
173 | solveButton.setMnemonic('s'); |
174 | solveButton.setText("Solve"); |
175 | solveButton.addActionListener(new java.awt.event.ActionListener() { |
176 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
177 | solveButtonActionPerformed(evt); |
178 | } |
179 | }); |
180 | |
181 | jPanel2.add(solveButton); |
182 | |
183 | hintButton.setMnemonic('t'); |
184 | hintButton.setText("Hint"); |
185 | hintButton.setEnabled(false); |
186 | hintButton.addActionListener(new java.awt.event.ActionListener() { |
187 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
188 | hintButtonActionPerformed(evt); |
189 | } |
190 | }); |
191 | |
192 | jPanel2.add(hintButton); |
193 | |
194 | getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH); |
195 | |
196 | fileMenu.setMnemonic('f'); |
197 | fileMenu.setText("File"); |
198 | newMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK)); |
199 | newMenuItem.setMnemonic('n'); |
200 | newMenuItem.setText("New..."); |
201 | newMenuItem.addActionListener(new java.awt.event.ActionListener() { |
202 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
203 | newMenuItemActionPerformed(evt); |
204 | } |
205 | }); |
206 | |
207 | fileMenu.add(newMenuItem); |
208 | |
209 | openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK)); |
210 | openMenuItem.setMnemonic('o'); |
211 | openMenuItem.setText("Open..."); |
212 | openMenuItem.addActionListener(new java.awt.event.ActionListener() { |
213 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
214 | openMenuItemActionPerformed(evt); |
215 | } |
216 | }); |
217 | |
218 | fileMenu.add(openMenuItem); |
219 | |
220 | saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK)); |
221 | saveMenuItem.setMnemonic('s'); |
222 | saveMenuItem.setText("Save"); |
223 | saveMenuItem.addActionListener(new java.awt.event.ActionListener() { |
224 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
225 | saveMenuItemActionPerformed(evt); |
226 | } |
227 | }); |
228 | |
229 | fileMenu.add(saveMenuItem); |
230 | |
231 | saveAsMenuItem.setMnemonic('a'); |
232 | saveAsMenuItem.setText("Save As..."); |
233 | saveAsMenuItem.addActionListener(new java.awt.event.ActionListener() { |
234 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
235 | saveAsMenuItemActionPerformed(evt); |
236 | } |
237 | }); |
238 | |
239 | fileMenu.add(saveAsMenuItem); |
240 | |
241 | fileMenu.add(jSeparator1); |
242 | |
243 | pageSetupMenuItem.setMnemonic('g'); |
244 | pageSetupMenuItem.setText("Page Setup..."); |
245 | pageSetupMenuItem.addActionListener(new java.awt.event.ActionListener() { |
246 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
247 | pageSetupMenuItemActionPerformed(evt); |
248 | } |
249 | }); |
250 | |
251 | fileMenu.add(pageSetupMenuItem); |
252 | |
253 | printMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, java.awt.event.InputEvent.CTRL_MASK)); |
254 | printMenuItem.setMnemonic('p'); |
255 | printMenuItem.setText("Print..."); |
256 | printMenuItem.addActionListener(new java.awt.event.ActionListener() { |
257 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
258 | printMenuItemActionPerformed(evt); |
259 | } |
260 | }); |
261 | |
262 | fileMenu.add(printMenuItem); |
263 | |
264 | fileMenu.add(jSeparator2); |
265 | |
266 | closeMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.CTRL_MASK)); |
267 | closeMenuItem.setMnemonic('c'); |
268 | closeMenuItem.setText("Close"); |
269 | fileMenu.add(closeMenuItem); |
270 | |
271 | menuBar.add(fileMenu); |
272 | |
273 | editMenu.setMnemonic('e'); |
274 | editMenu.setText("Edit"); |
275 | undoMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK)); |
276 | undoMenuItem.setMnemonic('u'); |
277 | undoMenuItem.setText("Undo"); |
278 | undoMenuItem.setEnabled(false); |
279 | editMenu.add(undoMenuItem); |
280 | |
281 | redoMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK)); |
282 | redoMenuItem.setMnemonic('r'); |
283 | redoMenuItem.setText("Redo"); |
284 | redoMenuItem.setEnabled(false); |
285 | editMenu.add(redoMenuItem); |
286 | |
287 | menuBar.add(editMenu); |
288 | |
289 | helpMenu.setMnemonic('h'); |
290 | helpMenu.setText("Help"); |
291 | contentsMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0)); |
292 | contentsMenuItem.setText("Contents"); |
293 | contentsMenuItem.setEnabled(false); |
294 | helpMenu.add(contentsMenuItem); |
295 | |
296 | aboutMenuItem.setMnemonic('a'); |
297 | aboutMenuItem.setText("About"); |
298 | aboutMenuItem.addActionListener(new java.awt.event.ActionListener() { |
299 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
300 | aboutMenuItemActionPerformed(evt); |
301 | } |
302 | }); |
303 | |
304 | helpMenu.add(aboutMenuItem); |
305 | |
306 | menuBar.add(helpMenu); |
307 | |
308 | setJMenuBar(menuBar); |
309 | |
310 | pack(); |
311 | }// </editor-fold>//GEN-END:initComponents |
312 | |
313 | private void pageSetupMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pageSetupMenuItemActionPerformed |
314 | log.debug("page setup"); |
315 | PrinterJob printJob = PrinterJob.getPrinterJob(); |
316 | // printJob.setPrintable(puzzlePanel); |
317 | PageFormat pf = printJob.pageDialog(printJob.defaultPage()); |
318 | // if (printJob.printDialog()) { |
319 | // try { |
320 | // printJob.print(); |
321 | // } catch (PrinterException e) { |
322 | // log.error("Error while printing: " + e.getLocalizedMessage(), e); |
323 | // } |
324 | // } |
325 | }//GEN-LAST:event_pageSetupMenuItemActionPerformed |
326 | |
327 | private void printMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_printMenuItemActionPerformed |
328 | log.debug("print grid"); |
329 | PrinterJob printJob = PrinterJob.getPrinterJob(); |
330 | printJob.setPrintable(puzzlePanel); |
331 | // PageFormat pf = printJob.pageDialog(printJob.defaultPage()); |
332 | if (printJob.printDialog()) { |
333 | try { |
334 | printJob.print(); |
335 | } catch (PrinterException e) { |
336 | log.error("Error while printing: " + e.getLocalizedMessage(), e); |
337 | } |
338 | } |
339 | }//GEN-LAST:event_printMenuItemActionPerformed |
340 | |
341 | private void playModeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playModeRadioButtonActionPerformed |
342 | switchToMode(ModeEnum.PLAY); |
343 | }//GEN-LAST:event_playModeRadioButtonActionPerformed |
344 | |
345 | private void hintButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hintButtonActionPerformed |
346 | log.debug("Get hint"); |
347 | if (!showSolutionCheckBox.isSelected() && |
348 | playModeRadioButton.isSelected() && |
349 | !puzzle.isComplete()) { |
350 | Solver solver = SolverFactory.newInstance(puzzle); |
351 | try { |
352 | SolutionStep solution = solver.solveOneCell(); |
353 | puzzle.getGrid().put(solution.getCoordinate(), |
354 | Integer.valueOf(solution.getValue())); |
355 | puzzlePanel.setCurrentCell(solution.getCoordinate()); |
356 | repaint(); |
357 | } catch (UnsolveablePuzzleException e) { |
358 | log.warn("Can't be solved"); |
359 | JOptionPane.showMessageDialog(this, |
360 | "Unable to solve puzzle.\n" + e.getLocalizedMessage(), |
361 | "No solution found", JOptionPane.ERROR_MESSAGE); |
362 | } |
363 | } else { |
364 | log.warn("Hint button should not be enabled currently"); |
365 | } |
366 | }//GEN-LAST:event_hintButtonActionPerformed |
367 | |
368 | private void solveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_solveButtonActionPerformed |
369 | log.debug("Solve puzzle"); |
370 | showSolutionCheckBox.setSelected(false); |
371 | puzzlePanel.setShowSolution(false); |
372 | Solver solver = SolverFactory.newInstance(puzzle); |
373 | try { |
374 | Solution solution = solver.solveEntirePuzzle(); |
375 | puzzle.setSolution(solution); |
376 | showSolutionCheckBox.setSelected(true); |
377 | puzzlePanel.setShowSolution(true); |
378 | } catch (UnsolveablePuzzleException e) { |
379 | log.warn("Can't be solved"); |
380 | JOptionPane.showMessageDialog(this, |
381 | "Unable to solve puzzle.\n" + e.getLocalizedMessage(), |
382 | "No solution found", JOptionPane.ERROR_MESSAGE); |
383 | } |
384 | showSolutionCheckBox.setEnabled(puzzle.isSolved()); |
385 | repaint(); |
386 | }//GEN-LAST:event_solveButtonActionPerformed |
387 | |
388 | private void designModeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_designModeRadioButtonActionPerformed |
389 | boolean changeMode = true; |
390 | if (puzzle.isPlayed()) { |
391 | int answer = JOptionPane.showConfirmDialog(this, |
392 | "You sure? This will clear all guessed numbers from the grid.", |
393 | "Switch to Design mode", JOptionPane.YES_NO_OPTION); |
394 | changeMode = (answer == JOptionPane.YES_OPTION); |
395 | } |
396 | if (changeMode) { |
397 | switchToMode(ModeEnum.DESIGN); |
398 | } else { |
399 | playModeRadioButton.setSelected(true); |
400 | log.debug("Decided not to switch modes."); |
401 | } |
402 | }//GEN-LAST:event_designModeRadioButtonActionPerformed |
403 | |
404 | private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetButtonActionPerformed |
405 | if ((designModeRadioButton.isSelected() && !puzzle.getGivens().isEmpty()) || |
406 | playModeRadioButton.isSelected() && puzzle.isPlayed()) { |
407 | int answer = JOptionPane.showConfirmDialog(this, "You sure?", |
408 | "Reset grid", JOptionPane.YES_NO_OPTION); |
409 | if (answer == JOptionPane.YES_OPTION) { |
410 | log.debug("Reset grid"); |
411 | if (designModeRadioButton.isSelected()) { |
412 | // design mode |
413 | puzzle.reset(); |
414 | } else { |
415 | // play mode |
416 | puzzle.resetToGivens(); |
417 | } |
418 | showSolutionCheckBox.setSelected(false); |
419 | puzzlePanel.setShowSolution(false); |
420 | repaint(); |
421 | } else if (answer == JOptionPane.NO_OPTION) { |
422 | log.debug("Decided not to reset"); |
423 | } |
424 | } |
425 | }//GEN-LAST:event_resetButtonActionPerformed |
426 | |
427 | private void puzzlePanelPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_puzzlePanelPropertyChange |
428 | if ("currentCell".equals(evt.getPropertyName())) { |
429 | Integer value = null; |
430 | if (showSolutionCheckBox.isSelected()) { |
431 | value = puzzle.getSolution().getGrid().get((Coordinate) evt.getNewValue()); |
432 | } else { |
433 | value = puzzle.getGrid().get((Coordinate) evt.getNewValue()); |
434 | } |
435 | if (value != null) { |
436 | int i = value.intValue(); |
437 | if (i >= 0 && i < digitButtons.length) { |
438 | digitButtons[i].setSelected(true); |
439 | } else { |
440 | log.warn("puzzle contains digit with no button?"); |
441 | } |
442 | } else { |
443 | log.warn("puzzlePanel changed to an invalid cell"); |
444 | } |
445 | } |
446 | }//GEN-LAST:event_puzzlePanelPropertyChange |
447 | |
448 | private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsMenuItemActionPerformed |
449 | File selectedFile = null; |
450 | |
451 | // Save file dialog. |
452 | JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir")); |
453 | fileChooser.addChoosableFileFilter( |
454 | new javax.swing.filechooser.FileFilter() { |
455 | public boolean accept(java.io.File file) { |
456 | if (file.isDirectory()) { |
457 | return true; |
458 | } |
459 | String filename = file.getName(); |
460 | return filename.endsWith(".xml"); |
461 | } |
462 | public String getDescription() { |
463 | return "XML files (*.xml)"; |
464 | } |
465 | }); |
466 | fileChooser.setFileFilter( |
467 | new javax.swing.filechooser.FileFilter() { |
468 | public boolean accept(java.io.File file) { |
469 | if (file.isDirectory()) { |
470 | return true; |
471 | } |
472 | String filename = file.getName(); |
473 | return filename.endsWith(".pdq"); |
474 | } |
475 | public String getDescription() { |
476 | return "PseudoQ puzzles (*.pdq)"; |
477 | } |
478 | }); |
479 | |
480 | int result = fileChooser.showSaveDialog(this); |
481 | if (result == JFileChooser.APPROVE_OPTION) { |
482 | selectedFile = fileChooser.getSelectedFile(); |
483 | if (selectedFile.exists()) { |
484 | int answer = JOptionPane.showConfirmDialog(this, |
485 | "Replace existing " + selectedFile.getName() + "?", |
486 | "Overwrite file", JOptionPane.YES_NO_OPTION); |
487 | if (answer == JOptionPane.YES_OPTION) { |
488 | log.debug("Overwrite " + selectedFile.getPath()); |
489 | } else if (answer == JOptionPane.NO_OPTION) { |
490 | log.debug("Decided not to overwrite " + selectedFile.getPath()); |
491 | selectedFile = null; |
492 | } |
493 | } else { |
494 | log.debug("Save " + selectedFile.getPath()); |
495 | } |
496 | } else { |
497 | log.debug("Forget it"); |
498 | } |
499 | |
500 | if (selectedFile != null) { |
501 | try { |
502 | saveDocument(selectedFile.getPath()); |
503 | } catch (java.io.IOException e) { |
504 | log.error("IO Problem: " + e.getLocalizedMessage(), e); |
505 | } |
506 | puzzle.setFilename(selectedFile.getPath()); |
507 | setTitle("PseudoQ - " + removePath(selectedFile.getPath())); |
508 | } |
509 | }//GEN-LAST:event_saveAsMenuItemActionPerformed |
510 | |
511 | private String removePath(String filename) { |
512 | assert (filename != null); |
513 | |
514 | String retval = null; |
515 | |
516 | int pos = filename.lastIndexOf(File.separator); |
517 | if (pos >= 0 && pos < filename.length()) { |
518 | retval = filename.substring(pos + 1); |
519 | } else { |
520 | retval = filename; |
521 | } |
522 | |
523 | return retval; |
524 | } |
525 | |
526 | private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed |
527 | if (puzzle.getFilename() != null) { |
528 | log.debug("Save " + puzzle.getFilename()); |
529 | try { |
530 | saveDocument(puzzle.getFilename()); |
531 | } catch (java.io.IOException e) { |
532 | log.error("IO Problem : " + e.getLocalizedMessage(), e); |
533 | } |
534 | } else { |
535 | saveAsMenuItemActionPerformed(evt); |
536 | } |
537 | }//GEN-LAST:event_saveMenuItemActionPerformed |
538 | |
539 | private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed |
540 | javax.swing.SwingUtilities.invokeLater(new Runnable() { |
541 | public void run() { |
542 | new AboutDialog(PuzzleFrame.this, true).setVisible(true); |
543 | } |
544 | }); |
545 | }//GEN-LAST:event_aboutMenuItemActionPerformed |
546 | |
547 | private void newMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newMenuItemActionPerformed |
548 | NewPuzzleWizard wizard = new NewPuzzleWizard(); |
549 | |
550 | wizard.showInDialog("Create new puzzle", this, true); |
551 | if (!wizard.wasCanceled()) { |
552 | if (wizard.isGenerate()) { |
553 | log.debug("Generate new " + wizard.getPuzzleType() + " puzzle."); |
554 | // PuzzleFactory.generate(wizard.getPuzzleType()) |
555 | } else { |
556 | log.debug("Design new " + wizard.getPuzzleType() + " puzzle."); |
557 | final Puzzle puzzle = PuzzleFactory.newInstance(wizard.getPuzzleType()); |
558 | javax.swing.SwingUtilities.invokeLater(new Runnable() { |
559 | public void run() { |
560 | new PuzzleFrame(puzzle).setVisible(true); |
561 | } |
562 | }); |
563 | } |
564 | this.dispose(); |
565 | } else { |
566 | log.debug("No puzzle right now."); |
567 | } |
568 | }//GEN-LAST:event_newMenuItemActionPerformed |
569 | |
570 | private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed |
571 | // Open file dialog. |
572 | JFileChooser fileChooser = new JFileChooser(System.getProperty("user.dir")); |
573 | fileChooser.addChoosableFileFilter( |
574 | new javax.swing.filechooser.FileFilter() { |
575 | public boolean accept(java.io.File file) { |
576 | if (file.isDirectory()) { |
577 | return true; |
578 | } |
579 | String filename = file.getName(); |
580 | return filename.endsWith(".xml"); |
581 | } |
582 | public String getDescription() { |
583 | return "XML files (*.xml)"; |
584 | } |
585 | }); |
586 | fileChooser.setFileFilter( |
587 | new javax.swing.filechooser.FileFilter() { |
588 | public boolean accept(java.io.File file) { |
589 | if (file.isDirectory()) { |
590 | return true; |
591 | } |
592 | String filename = file.getName(); |
593 | return filename.endsWith(".pdq"); |
594 | } |
595 | public String getDescription() { |
596 | return "PseudoQ puzzles (*.pdq)"; |
597 | } |
598 | }); |
599 | |
600 | int result = fileChooser.showOpenDialog(this); |
601 | if (result == JFileChooser.APPROVE_OPTION) { |
602 | String selectedFile = fileChooser.getSelectedFile().getPath(); |
603 | log.debug("Open " + selectedFile); |
604 | try { |
605 | final Puzzle puzzle = PuzzleFileReader.read(selectedFile); |
606 | javax.swing.SwingUtilities.invokeLater(new Runnable() { |
607 | public void run() { |
608 | new PuzzleFrame(puzzle).setVisible(true); |
609 | } |
610 | }); |
611 | this.dispose(); |
612 | } catch (java.io.IOException e) { |
613 | log.error("IO Problem: " + e.getLocalizedMessage(), e); |
614 | JOptionPane.showMessageDialog(this, |
615 | "I/O error reading file:\n" + e.getLocalizedMessage(), |
616 | "File Read Error", JOptionPane.ERROR_MESSAGE); |
617 | } catch (javax.xml.parsers.ParserConfigurationException e) { |
618 | log.error("XML parser problem: " + e.getLocalizedMessage(), e); |
619 | JOptionPane.showMessageDialog(this, |
620 | "Invalid file.\nCouldn't parse file contents:\n" + e.getLocalizedMessage(), |
621 | "File Read Error", JOptionPane.ERROR_MESSAGE); |
622 | } |
623 | } else { |
624 | log.debug("Forget it"); |
625 | } |
626 | }//GEN-LAST:event_openMenuItemActionPerformed |
627 | |
628 | private void showSolutionCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_showSolutionCheckBoxItemStateChanged |
629 | int select = evt.getStateChange(); |
630 | if (select == ItemEvent.SELECTED && puzzle.isSolved()) { |
631 | puzzlePanel.setShowSolution(true); |
632 | } else { |
633 | puzzlePanel.setShowSolution(false); |
634 | } |
635 | }//GEN-LAST:event_showSolutionCheckBoxItemStateChanged |
636 | |
637 | // /** |
638 | // * @param args the command line arguments |
639 | // */ |
640 | // public static void main(String args[]) { |
641 | // java.awt.EventQueue.invokeLater(new Runnable() { |
642 | // public void run() { |
643 | // new PuzzleFrame().setVisible(true); |
644 | // } |
645 | // }); |
646 | // } |
647 | |
648 | // Variables declaration - do not modify//GEN-BEGIN:variables |
649 | javax.swing.JMenuItem aboutMenuItem; |
650 | javax.swing.ButtonGroup buttonGroup1; |
651 | javax.swing.ButtonGroup buttonGroup2; |
652 | javax.swing.JMenuItem closeMenuItem; |
653 | javax.swing.JMenuItem contentsMenuItem; |
654 | javax.swing.JRadioButton designModeRadioButton; |
655 | javax.swing.JPanel digitButtonPanel; |
656 | javax.swing.JMenu editMenu; |
657 | javax.swing.JMenu fileMenu; |
658 | javax.swing.JMenu helpMenu; |
659 | javax.swing.JButton hintButton; |
660 | javax.swing.JPanel jPanel1; |
661 | javax.swing.JPanel jPanel2; |
662 | javax.swing.JSeparator jSeparator1; |
663 | javax.swing.JSeparator jSeparator2; |
664 | javax.swing.JMenuBar menuBar; |
665 | javax.swing.JMenuItem newMenuItem; |
666 | javax.swing.JMenuItem openMenuItem; |
667 | javax.swing.JMenuItem pageSetupMenuItem; |
668 | javax.swing.JRadioButton playModeRadioButton; |
669 | javax.swing.JMenuItem printMenuItem; |
670 | net.sourceforge.pseudoq.gui.PuzzlePanel puzzlePanel; |
671 | javax.swing.JMenuItem redoMenuItem; |
672 | javax.swing.JButton resetButton; |
673 | javax.swing.JMenuItem saveAsMenuItem; |
674 | javax.swing.JMenuItem saveMenuItem; |
675 | javax.swing.JCheckBox showSolutionCheckBox; |
676 | javax.swing.JButton solveButton; |
677 | javax.swing.JMenuItem undoMenuItem; |
678 | // End of variables declaration//GEN-END:variables |
679 | |
680 | /** Array for dynamically created buttons in right-hand panel. */ |
681 | javax.swing.JToggleButton[] digitButtons; |
682 | |
683 | /** |
684 | * Holds value of property puzzle. |
685 | */ |
686 | private net.sourceforge.pseudoq.model.Puzzle puzzle; |
687 | |
688 | /** |
689 | * Getter for property puzzle. |
690 | * @return Value of property puzzle. |
691 | */ |
692 | public net.sourceforge.pseudoq.model.Puzzle getPuzzle() { |
693 | return this.puzzle; |
694 | } |
695 | |
696 | /** |
697 | * Setter for property puzzle. |
698 | * @param puzzle New value of property puzzle. |
699 | */ |
700 | public void setPuzzle(net.sourceforge.pseudoq.model.Puzzle puzzle) { |
701 | this.puzzle = puzzle; |
702 | } |
703 | |
704 | private void createDigitButton(int i) { |
705 | JToggleButton button = new JToggleButton(); |
706 | digitButtons[i] = button; |
707 | buttonGroup2.add(button); |
708 | button.setText(Grid.digit(i)); |
709 | button.addItemListener(new java.awt.event.ItemListener() { |
710 | public void itemStateChanged(java.awt.event.ItemEvent evt) { |
711 | digitButtonItemStateChanged(evt); |
712 | } |
713 | }); |
714 | digitButtonPanel.add(button); |
715 | } |
716 | |
717 | /** |
718 | * ItemEvent listener callback, triggered when any of the dynamically |
719 | * generated buttons are pressed. |
720 | */ |
721 | private void digitButtonItemStateChanged(java.awt.event.ItemEvent evt) { |
722 | int digit = -1; |
723 | for (int i = 0; i < digitButtons.length; i++) { |
724 | if (evt.getItem() == digitButtons[i]) { |
725 | digit = i; |
726 | } |
727 | } |
728 | if (digit >= 0) { |
729 | if (puzzlePanel.getCurrentCell() != null && |
730 | puzzle.getGrid().get(puzzlePanel.getCurrentCell()) != null) { |
731 | if (designModeRadioButton.isSelected()) { |
732 | // design mode, can change any cell |
733 | puzzle.getGrid().put(puzzlePanel.getCurrentCell(), Integer.valueOf(digit)); |
734 | if (digit == 0) { |
735 | puzzle.getGivens().remove(puzzlePanel.getCurrentCell()); |
736 | } else { |
737 | puzzle.getGivens().add(puzzlePanel.getCurrentCell()); |
738 | } |
739 | } else { |
740 | // play mode, can't change givens |
741 | if (!puzzle.getGivens().contains(puzzlePanel.getCurrentCell())) { |
742 | puzzle.getGrid().put(puzzlePanel.getCurrentCell(), Integer.valueOf(digit)); |
743 | } |
744 | } |
745 | repaint(); |
746 | } |
747 | } |
748 | } |
749 | |
750 | private void saveDocument(String filename) throws java.io.IOException { |
751 | PuzzleFileWriter.write(filename, puzzle); |
752 | } |
753 | |
754 | private void switchToMode(ModeEnum mode) { |
755 | if (mode.equals(ModeEnum.DESIGN)) { |
756 | log.debug("Switching to design mode; clear non-givens."); |
757 | puzzle.resetToGivens(); |
758 | showSolutionCheckBox.setSelected(false); |
759 | hintButton.setEnabled(false); |
760 | repaint(); |
761 | } else if (mode.equals(ModeEnum.PLAY)) { |
762 | log.debug("Switching to play mode"); |
763 | hintButton.setEnabled(true); |
764 | repaint(); |
765 | } |
766 | } |
767 | |
768 | } |