001 package view; 002 003 import controller.IDisplayAdapter; 004 import controller.IEnvAdapter; 005 006 import javax.swing.*; 007 import java.awt.*; 008 import java.awt.event.MouseAdapter; 009 import java.awt.event.MouseEvent; 010 import java.awt.geom.AffineTransform; 011 012 /** 013 * Panel to display the environment. 014 * 015 * @author Mathias Ricken 016 */ 017 public class DisplayPanel extends JPanel implements Scrollable, DisplayViewport.Pannable { 018 // Class constants 019 private static final int MIN_CELL_SIZE = 8; 020 private static final int DEFAULT_CELL_SIZE = 32; 021 022 /** 023 * Display adapter. 024 */ 025 IDisplayAdapter _displayAdapter; 026 027 /** 028 * Cell size. 029 */ 030 int _cellSize = DEFAULT_CELL_SIZE; 031 032 /** 033 * Origin column. 034 */ 035 double _originX; 036 037 /** 038 * Origin row. 039 */ 040 double _originY; 041 042 /** 043 * Mouse adapter for editing. 044 */ 045 MouseAdapter _mouseAdapter; 046 047 /** 048 * State of tool tips. 049 */ 050 private boolean _toolTipsEnabled; 051 052 /** 053 * Environment adapter. 054 */ 055 IEnvAdapter _envAdapter; 056 057 /** 058 * Make a new display panel. 059 * 060 * @param da display adapter to use 061 * @param ea environment adapter to use 062 */ 063 public DisplayPanel(IDisplayAdapter da, final IEnvAdapter ea) { 064 _displayAdapter = da; 065 _envAdapter = ea; 066 _mouseAdapter = new MouseAdapter() { 067 public void mousePressed(MouseEvent evt) { 068 double x = ((double)evt.getPoint().x) / _cellSize + _originX; 069 double y = ((double)evt.getPoint().y) / _cellSize + _originY; 070 071 ea.edit(new Point.Double(x, y), evt.getButton()); 072 revalidate(); 073 } 074 }; 075 setToolTipsEnabled(true); 076 revalidate(); 077 } 078 079 /** 080 * Enable or disable the mouse adapter for editing. 081 * 082 * @param enable true to enable 083 */ 084 public void enableMouseAdapter(boolean enable) { 085 if (enable) { 086 addMouseListener(_mouseAdapter); 087 } 088 else { 089 removeMouseListener(_mouseAdapter); 090 } 091 } 092 093 /** 094 * Enable or disable showing of tooltip giving information about the environment object beneath the mouse. 095 * 096 * @param flag whether to enable/disable tool tips 097 */ 098 public void setToolTipsEnabled(boolean flag) { 099 if (flag) { 100 ToolTipManager.sharedInstance().registerComponent(this); 101 } 102 else { 103 ToolTipManager.sharedInstance().unregisterComponent(this); 104 } 105 _toolTipsEnabled = flag; 106 } 107 108 /** 109 * Given a MouseEvent, determine what text to place in the floating tool tip when the the mouse hovers over this 110 * location. If the mouse is over a valid environment cell. we provide some information about the cell and its 111 * contents. This method is automatically called on mouse-moved events since we register for tool tips. 112 * 113 * @param evt the MouseEvent in question 114 * 115 * @return the tool tip string for this location 116 */ 117 public String getToolTipText(MouseEvent evt) { 118 double x = ((double)evt.getPoint().x) / _cellSize + _originX; 119 double y = ((double)evt.getPoint().y) / _cellSize + _originY; 120 return _envAdapter.getToolTipText(new Point.Double(x, y)); 121 } 122 123 /** 124 * Zoom in. 125 */ 126 public void zoomIn() { 127 double oldOriginX = _originX; 128 double oldOriginY = _originY; 129 JViewport vp = (JViewport)getParent(); 130 Point pt = vp.getViewPosition(); 131 pt.x = (int)(((double)pt.x) / _cellSize + _originX); 132 pt.y = (int)(((double)pt.y) / _cellSize + _originY); 133 134 _cellSize *= 2; 135 setCorner(pt.x, pt.y); 136 _originX = oldOriginX; 137 _originY = oldOriginY; 138 revalidate(); 139 } 140 141 /** 142 * Zoom out. 143 */ 144 public void zoomOut() { 145 double oldOriginX = _originX; 146 double oldOriginY = _originY; 147 JViewport vp = (JViewport)getParent(); 148 Point pt = vp.getViewPosition(); 149 pt.x = (int)(((double)pt.x) / _cellSize + _originX); 150 pt.y = (int)(((double)pt.y) / _cellSize + _originY); 151 152 _cellSize = Math.max(MIN_CELL_SIZE, _cellSize / 2); 153 setCorner(pt.x, pt.y); 154 _originX = oldOriginX; 155 _originY = oldOriginY; 156 revalidate(); 157 } 158 159 /** 160 * Make field (x,y) visible in top left corner. 161 * 162 * @param x x-coordinate 163 * @param y y-coordinate 164 */ 165 public void setCorner(int x, int y) { 166 DisplayViewport vp = (DisplayViewport)getParent(); 167 vp.oldSetViewPosition(new Point((int)(x - _originX) * _cellSize, (int)(y - _originY) * _cellSize)); 168 } 169 170 /** 171 * Returns the desired size of the display, for use by layout manager. 172 * 173 * @return preferred size 174 */ 175 public Dimension getPreferredSize() { 176 Dimension s = _displayAdapter.getDisplaySize(); 177 return new Dimension(s.width * _cellSize, s.height * _cellSize); 178 } 179 180 /** 181 * Returns the minimum size of the display, for use by layout manager. 182 * 183 * @return minimum size 184 */ 185 public Dimension getMinimumSize() { 186 Dimension s = _displayAdapter.getDisplaySize(); 187 return new Dimension(s.width * MIN_CELL_SIZE, s.height * MIN_CELL_SIZE); 188 } 189 190 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 191 return _cellSize; 192 } 193 194 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 195 if (SwingConstants.VERTICAL == orientation) { 196 return (int)(visibleRect.height * .9); 197 } 198 else { 199 return (int)(visibleRect.width * .9); 200 } 201 } 202 203 public boolean getScrollableTracksViewportWidth() { 204 return false; 205 } 206 207 public boolean getScrollableTracksViewportHeight() { 208 return false; 209 } 210 211 public Dimension getPreferredScrollableViewportSize() { 212 return new Dimension(420, 420); 213 } 214 215 /** 216 * Paint this component. 217 * 218 * @param g the Graphics object to use to render this component 219 */ 220 public void paintComponent(Graphics g) { 221 Graphics2D g2 = (Graphics2D)g; 222 super.paintComponent(g2); 223 224 Rectangle curClip = g2.getClipBounds(); 225 Graphics2D envGraphics = (Graphics2D)g2.create(); 226 AffineTransform oldTransform = envGraphics.getTransform(); 227 int left = getInsets().left; 228 int top = getInsets().top; 229 230 // transform to model coordinates 231 int x1 = (curClip.x - left) / _cellSize; 232 int y1 = (curClip.y - top) / _cellSize; 233 int x2 = (curClip.x + curClip.width - left + _cellSize - 1) / _cellSize; 234 int y2 = (curClip.y + curClip.height - top + _cellSize - 1) / _cellSize; 235 236 // translate and scale so that (0,0) corresponds to the field (x1,y1) in model coordinates 237 // and each field in model coordinates is MODEL_CELL_SIZE wide 238 envGraphics.translate(x1 * _cellSize + left, y1 * _cellSize + top); 239 envGraphics.scale(_cellSize, _cellSize); 240 envGraphics.setStroke(new BasicStroke(1.0f / _cellSize)); 241 _displayAdapter.draw(envGraphics, 242 this, 243 new Point.Double(x1 + (int)_originX, y1 + (int)_originY), 244 new Point.Double(x2 + (int)_originX, y2 + (int)_originY)); 245 246 envGraphics.setTransform(oldTransform); 247 } 248 249 /** 250 * Pan the panel by the specified amount of pixels. 251 * 252 * @param dx horizontal pan in pixels 253 * @param dy vertical pan in pixels 254 */ 255 public void pan(double dx, double dy) { 256 _originX = (int)(_originX + dx / _cellSize); 257 _originY = (int)(_originY + dy / _cellSize); 258 } 259 260 /** 261 * Return the current cell size. 262 * 263 * @return cell size 264 */ 265 public int getCellSize() { 266 return _cellSize; 267 } 268 269 /** 270 * Reset the pan. 271 */ 272 public void resetPan() { 273 Point.Double center = _displayAdapter.getViewPosition(new Point.Double(0, 0)); 274 _originX = -center.x; 275 _originY = -center.y; 276 repaint(); 277 } 278 279 /** 280 * Get the tool tip text for panning. 281 * 282 * @return pan tool tip 283 */ 284 public String getPanTipText() { 285 JViewport vp = (JViewport)getParent(); 286 Point pt = vp.getViewPosition(); 287 int x = (int)(((double)pt.x) / _cellSize + _originX); 288 int y = (int)(((double)pt.y) / _cellSize + _originY); 289 return "(" + x + ',' + y + ')'; 290 } 291 }