| 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.Dimension; |
| 24 | import java.awt.Graphics2D; |
| 25 | import javax.swing.RepaintManager; |
| 26 | |
| 27 | import net.sourceforge.pseudoq.model.Coordinate; |
| 28 | |
| 29 | /** |
| 30 | * Custom swing component for displaying and editing a puzzle. |
| 31 | * @author <a href="http://sourceforge.net/users/stevensa">Andrew Stevens</a> |
| 32 | */ |
| 33 | public class PuzzlePanel extends javax.swing.JComponent implements java.awt.print.Printable { |
| 34 | /** Log4J logger */ |
| 35 | private static final org.apache.log4j.Logger log = |
| 36 | org.apache.log4j.LogManager.getLogger(PuzzlePanel.class); |
| 37 | |
| 38 | /** Creates new form PuzzlePanel */ |
| 39 | public PuzzlePanel() { |
| 40 | initComponents(); |
| 41 | } |
| 42 | |
| 43 | /** This method is called from within the constructor to |
| 44 | * initialize the form. |
| 45 | * WARNING: Do NOT modify this code. The content of this method is |
| 46 | * always regenerated by the Form Editor. |
| 47 | */ |
| 48 | // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents |
| 49 | private void initComponents() { |
| 50 | |
| 51 | setLayout(new java.awt.BorderLayout()); |
| 52 | |
| 53 | addMouseListener(new java.awt.event.MouseAdapter() { |
| 54 | public void mousePressed(java.awt.event.MouseEvent evt) { |
| 55 | formMousePressed(evt); |
| 56 | } |
| 57 | }); |
| 58 | |
| 59 | } |
| 60 | // </editor-fold>//GEN-END:initComponents |
| 61 | |
| 62 | private void formMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMousePressed |
| 63 | // figure out what cell was clicked on |
| 64 | int x = (evt.getX() - 5) / painter.getSize(); |
| 65 | int y = (evt.getY() - 5) / painter.getSize(); |
| 66 | if (x >= 0 && x < puzzle.getSize() && y >= 0 && y < puzzle.getSize()) { |
| 67 | Coordinate newCell = new Coordinate(y, x); |
| 68 | if ((currentCell == null || !currentCell.equals(newCell)) && puzzle.getGrid().get(newCell) != null) { |
| 69 | setCurrentCell(newCell); |
| 70 | repaint(); |
| 71 | } |
| 72 | } |
| 73 | }//GEN-LAST:event_formMousePressed |
| 74 | |
| 75 | // Variables declaration - do not modify//GEN-BEGIN:variables |
| 76 | // End of variables declaration//GEN-END:variables |
| 77 | |
| 78 | /** |
| 79 | * Holds painter to be used to draw the grid. |
| 80 | */ |
| 81 | private GridPainter painter = null; |
| 82 | /** |
| 83 | * Holds value of property puzzle. |
| 84 | */ |
| 85 | private net.sourceforge.pseudoq.model.Puzzle puzzle; |
| 86 | /** |
| 87 | * Holds value of property showSolution. |
| 88 | */ |
| 89 | private boolean showSolution; |
| 90 | /** |
| 91 | * Holds value of property currentCell. |
| 92 | */ |
| 93 | private Coordinate currentCell; |
| 94 | |
| 95 | /** |
| 96 | * Getter for property puzzle. |
| 97 | * @return Value of property puzzle. |
| 98 | */ |
| 99 | public net.sourceforge.pseudoq.model.Puzzle getPuzzle() { |
| 100 | return this.puzzle; |
| 101 | } |
| 102 | |
| 103 | /** |
| 104 | * Setter for property puzzle. |
| 105 | * @param puzzle New value of property puzzle. |
| 106 | */ |
| 107 | public void setPuzzle(net.sourceforge.pseudoq.model.Puzzle puzzle) { |
| 108 | this.puzzle = puzzle; |
| 109 | painter = GridPainterFactory.newInstance(puzzle.getType()); |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Getter for property showSolution. |
| 114 | * @return Value of property showSolution. |
| 115 | */ |
| 116 | public boolean isShowSolution() { |
| 117 | return this.showSolution; |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Setter for property showSolution. |
| 122 | * @param showSolution New value of property showSolution. |
| 123 | */ |
| 124 | public void setShowSolution(boolean showSolution) { |
| 125 | this.showSolution = showSolution; |
| 126 | repaint(); |
| 127 | } |
| 128 | |
| 129 | public void paintComponent(java.awt.Graphics g) { |
| 130 | super.paintComponent(g); |
| 131 | if (painter != null) { |
| 132 | painter.drawGrid(g); |
| 133 | if (showSolution && puzzle.isSolved()) { |
| 134 | painter.printValues(g, puzzle.getSolution().getGrid(), puzzle.getGivens()); |
| 135 | } else { |
| 136 | painter.printValues(g, puzzle.getGrid(), puzzle.getGivens()); |
| 137 | } |
| 138 | if (currentCell != null) { |
| 139 | painter.highlightCell(g, currentCell); |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | public Dimension getPreferredSize() { |
| 145 | Dimension retval = null; |
| 146 | |
| 147 | if (painter != null) { |
| 148 | retval = painter.getPreferredSize(); |
| 149 | } else { |
| 150 | retval = new Dimension(100, 100); |
| 151 | } |
| 152 | |
| 153 | return retval; |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Utility field used by event firing mechanism. |
| 158 | */ |
| 159 | private javax.swing.event.EventListenerList listenerList = null; |
| 160 | |
| 161 | /** |
| 162 | * Utility field used by bound properties. |
| 163 | */ |
| 164 | private java.beans.PropertyChangeSupport propertyChangeSupport = |
| 165 | new java.beans.PropertyChangeSupport(this); |
| 166 | |
| 167 | /** |
| 168 | * Adds a PropertyChangeListener to the listener list. |
| 169 | * @param l The listener to add. |
| 170 | */ |
| 171 | public void addPropertyChangeListener(java.beans.PropertyChangeListener l) { |
| 172 | propertyChangeSupport.addPropertyChangeListener(l); |
| 173 | } |
| 174 | |
| 175 | /** |
| 176 | * Removes a PropertyChangeListener from the listener list. |
| 177 | * @param l The listener to remove. |
| 178 | */ |
| 179 | public void removePropertyChangeListener(java.beans.PropertyChangeListener l) { |
| 180 | propertyChangeSupport.removePropertyChangeListener(l); |
| 181 | } |
| 182 | |
| 183 | /** |
| 184 | * Getter for property currentCell. |
| 185 | * @return Value of property currentCell. |
| 186 | */ |
| 187 | public Coordinate getCurrentCell() { |
| 188 | return this.currentCell; |
| 189 | } |
| 190 | |
| 191 | /** |
| 192 | * Setter for property currentCell. |
| 193 | * @param currentCell New value of property currentCell. |
| 194 | */ |
| 195 | public void setCurrentCell(Coordinate currentCell) { |
| 196 | Coordinate oldCurrentCell = this.currentCell; |
| 197 | this.currentCell = currentCell; |
| 198 | propertyChangeSupport.firePropertyChange("currentCell", oldCurrentCell, currentCell); |
| 199 | } |
| 200 | |
| 201 | public int print(java.awt.Graphics g, java.awt.print.PageFormat pageFormat, int pageIndex) |
| 202 | throws java.awt.print.PrinterException { |
| 203 | int retval = 0; |
| 204 | |
| 205 | if (pageIndex > 0) { |
| 206 | retval = NO_SUCH_PAGE; |
| 207 | } else { |
| 208 | Graphics2D g2d = (Graphics2D) g; |
| 209 | |
| 210 | // don't print cursor |
| 211 | Coordinate oldCurrentCell = this.currentCell; |
| 212 | this.currentCell = null; |
| 213 | // move to the printable area |
| 214 | g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); |
| 215 | // check if the puzzle is bigger than the page, and scale to fit |
| 216 | Dimension size = painter.getPreferredSize(); |
| 217 | if (pageFormat.getImageableWidth() < size.getWidth() || |
| 218 | pageFormat.getImageableHeight() < size.getHeight()) { |
| 219 | double scalingFactor = Math.min(pageFormat.getImageableWidth() / size.getWidth(), |
| 220 | pageFormat.getImageableHeight() / size.getHeight()); |
| 221 | g2d.scale(scalingFactor, scalingFactor); |
| 222 | } |
| 223 | // disable double buffering while printing, as it's unnecessary |
| 224 | RepaintManager manager = RepaintManager.currentManager(this); |
| 225 | manager.setDoubleBufferingEnabled(false); |
| 226 | // print grid |
| 227 | this.paint(g2d); |
| 228 | // restore previous state |
| 229 | manager.setDoubleBufferingEnabled(true); |
| 230 | this.currentCell = oldCurrentCell; |
| 231 | |
| 232 | retval = PAGE_EXISTS; |
| 233 | } |
| 234 | |
| 235 | return retval; |
| 236 | } |
| 237 | |
| 238 | /** |
| 239 | * Get the painter that will be used to draw the grid. |
| 240 | * @return The painter. |
| 241 | */ |
| 242 | GridPainter getPainter() { |
| 243 | return this.painter; |
| 244 | } |
| 245 | |
| 246 | } |