001 /* 002 * Copyright (C) 2008-2010 by Holger Arndt 003 * 004 * This file is part of the Universal Java Matrix Package (UJMP). 005 * See the NOTICE file distributed with this work for additional 006 * information regarding copyright ownership and licensing. 007 * 008 * UJMP is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation; either version 2 011 * of the License, or (at your option) any later version. 012 * 013 * UJMP is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public 019 * License along with UJMP; if not, write to the 020 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 021 * Boston, MA 02110-1301 USA 022 */ 023 024 package org.ujmp.gui.panels; 025 026 import java.awt.AlphaComposite; 027 import java.awt.BasicStroke; 028 import java.awt.Color; 029 import java.awt.Dimension; 030 import java.awt.Graphics; 031 import java.awt.Graphics2D; 032 import java.awt.event.ComponentEvent; 033 import java.awt.event.ComponentListener; 034 import java.awt.event.MouseEvent; 035 import java.awt.event.MouseListener; 036 import java.awt.event.MouseMotionListener; 037 import java.awt.image.BufferedImage; 038 import java.io.File; 039 040 import javax.swing.Action; 041 import javax.swing.BorderFactory; 042 import javax.swing.JComponent; 043 import javax.swing.JMenuItem; 044 import javax.swing.JPanel; 045 import javax.swing.JPopupMenu; 046 import javax.swing.ToolTipManager; 047 import javax.swing.UIManager; 048 import javax.swing.event.ListSelectionEvent; 049 import javax.swing.event.ListSelectionListener; 050 import javax.swing.event.TableModelEvent; 051 import javax.swing.event.TableModelListener; 052 053 import org.ujmp.core.Coordinates; 054 import org.ujmp.core.interfaces.HasToolTip; 055 import org.ujmp.gui.MatrixGUIObject; 056 import org.ujmp.gui.actions.MatrixActions; 057 import org.ujmp.gui.interfaces.CanBeRepainted; 058 import org.ujmp.gui.io.ExportJPEG; 059 import org.ujmp.gui.io.ExportPDF; 060 import org.ujmp.gui.io.ExportPNG; 061 import org.ujmp.gui.menu.MatrixPopupMenu; 062 import org.ujmp.gui.renderer.MatrixRenderer; 063 import org.ujmp.gui.util.GraphicsExecutor; 064 import org.ujmp.gui.util.TooltipUtil; 065 066 public class MatrixPaintPanel extends JPanel implements ComponentListener, 067 TableModelListener, MouseListener, MouseMotionListener, CanBeRepainted, 068 HasToolTip, ListSelectionListener { 069 private static final long serialVersionUID = 843653796010276950L; 070 071 private MatrixGUIObject matrix = null; 072 073 private final MatrixRenderer renderer = new MatrixRenderer(); 074 075 private BufferedImage bufferedImage = null; 076 077 private static int PADDINGX = UIManager.getInt("Table.paddingX"); 078 079 private static int PADDINGY = UIManager.getInt("Table.paddingY"); 080 081 private int startRow = 0; 082 083 private int startCol = 0; 084 085 private String oldToolTip = ""; 086 087 public MatrixPaintPanel(MatrixGUIObject matrix, boolean showBorder) { 088 if (showBorder) { 089 setBorder(BorderFactory.createTitledBorder("Matrix Visualization")); 090 } 091 092 addComponentListener(this); 093 addMouseListener(this); 094 addMouseMotionListener(this); 095 096 setPreferredSize(new Dimension(600, 400)); 097 098 setMatrix(matrix); 099 100 ToolTipManager.sharedInstance().registerComponent(this); 101 102 registerKeyboardActions(); 103 } 104 105 private void registerKeyboardActions() { 106 for (JComponent c : new MatrixActions(this, matrix, null)) { 107 if (c instanceof JMenuItem) { 108 registerKeyboardAction(((JMenuItem) c).getAction()); 109 } 110 } 111 } 112 113 private void registerKeyboardAction(Action a) { 114 // KeyStroke keyStroke = (KeyStroke) a.getValue(Action.ACCELERATOR_KEY); 115 // getActionMap().put(a.getValue(Action.NAME), a); 116 // getInputMap(WHEN_IN_FOCUSED_WINDOW).put(keyStroke, 117 // a.getValue(Action.NAME)); 118 } 119 120 public void componentHidden(ComponentEvent e) { 121 } 122 123 public void componentMoved(ComponentEvent e) { 124 } 125 126 public void componentResized(ComponentEvent e) { 127 renderer.setSize(getSize()); 128 GraphicsExecutor.scheduleUpdate(this); 129 } 130 131 public void componentShown(ComponentEvent e) { 132 } 133 134 public void tableChanged(TableModelEvent e) { 135 GraphicsExecutor.scheduleUpdate(this); 136 } 137 138 public void mouseClicked(MouseEvent e) { 139 if (matrix != null) { 140 141 if (e.getButton() == MouseEvent.BUTTON3) { 142 143 int newRow = getRowPos(e.getY()); 144 int newCol = getColPos(e.getX()); 145 146 newRow = newRow < 0 ? 0 : newRow; 147 newCol = newCol < 0 ? 0 : newCol; 148 newRow = newRow >= matrix.getRowCount() ? matrix.getRowCount() - 1 149 : newRow; 150 newCol = newCol >= matrix.getColumnCount() ? matrix 151 .getColumnCount() - 1 : newCol; 152 153 JPopupMenu popup = new MatrixPopupMenu(this, matrix, newRow, 154 newCol); 155 popup.show(this, e.getX(), e.getY()); 156 } 157 } 158 } 159 160 public void mouseEntered(MouseEvent e) { 161 } 162 163 public void mouseExited(MouseEvent e) { 164 } 165 166 public void mousePressed(MouseEvent e) { 167 if (matrix != null) { 168 if (e.getButton() == MouseEvent.BUTTON1) { 169 startRow = getRowPos(e.getY()); 170 startCol = getColPos(e.getX()); 171 startRow = startRow < 0 ? 0 : startRow; 172 startCol = startCol < 0 ? 0 : startCol; 173 startRow = startRow >= matrix.getRowCount() ? matrix 174 .getRowCount() - 1 : startRow; 175 startCol = startCol >= matrix.getColumnCount() ? matrix 176 .getColumnCount() - 1 : startCol; 177 matrix.getRowSelectionModel().setValueIsAdjusting(true); 178 matrix.getColumnSelectionModel().setValueIsAdjusting(true); 179 matrix.getRowSelectionModel().setSelectionInterval(startRow, 180 startRow); 181 matrix.getColumnSelectionModel().setSelectionInterval(startCol, 182 startCol); 183 } 184 repaint(100); 185 } 186 } 187 188 private int getRowPos(int y) { 189 return (int) Math.floor((double) matrix.getRowCount() * (double) y 190 / getHeight()); 191 } 192 193 private int getColPos(int x) { 194 return (int) Math.floor((double) matrix.getColumnCount() * (double) x 195 / getWidth()); 196 } 197 198 public void mouseReleased(MouseEvent e) { 199 if (matrix != null) { 200 if (e.getButton() == MouseEvent.BUTTON1) { 201 int newRow = getRowPos(e.getY()); 202 int newCol = getColPos(e.getX()); 203 newRow = newRow < 0 ? 0 : newRow; 204 newCol = newCol < 0 ? 0 : newCol; 205 newRow = newRow >= matrix.getRowCount() ? matrix.getRowCount() - 1 206 : newRow; 207 newCol = newCol >= matrix.getColumnCount() ? matrix 208 .getColumnCount() - 1 : newCol; 209 matrix.getRowSelectionModel().setValueIsAdjusting(false); 210 matrix.getColumnSelectionModel().setValueIsAdjusting(false); 211 matrix.getRowSelectionModel().setSelectionInterval(startRow, 212 newRow); 213 matrix.getColumnSelectionModel().setSelectionInterval(startCol, 214 newCol); 215 repaint(100); 216 } 217 } 218 } 219 220 public MatrixGUIObject getMatrix() { 221 return matrix; 222 } 223 224 public String getToolTipText(MouseEvent e) { 225 // only generate tool text when there a matrix with size >0 is available 226 if (matrix != null && Coordinates.product(matrix.getSize()) != 0) { 227 int r = getRowPos(e.getY()); 228 int c = getColPos(e.getX()); 229 r = r < 0 ? 0 : r; 230 c = c < 0 ? 0 : c; 231 r = r >= matrix.getRowCount() ? matrix.getRowCount() - 1 : r; 232 c = c >= matrix.getColumnCount() ? matrix.getColumnCount() - 1 : c; 233 234 String toolTip = TooltipUtil.getTooltip(matrix, r, c); 235 if (("" + toolTip).length() == ("" + oldToolTip).length()) { 236 toolTip = toolTip + "\n"; 237 } 238 oldToolTip = toolTip; 239 return toolTip; 240 } else { 241 return null; 242 } 243 } 244 245 public void setMatrix(MatrixGUIObject m) { 246 if (matrix != null) { 247 matrix.removeTableModelListener(this); 248 matrix.getRowSelectionModel().removeListSelectionListener(this); 249 matrix.getColumnSelectionModel().removeListSelectionListener(this); 250 } 251 252 if (m != null) { 253 matrix = m; 254 renderer.setMatrix(m); 255 } else { 256 matrix = null; 257 } 258 259 if (matrix != null) { 260 matrix.addTableModelListener(this); 261 matrix.getRowSelectionModel().addListSelectionListener(this); 262 matrix.getColumnSelectionModel().addListSelectionListener(this); 263 } 264 265 GraphicsExecutor.scheduleUpdate(this); 266 } 267 268 protected void finalize() throws Throwable { 269 super.finalize(); 270 if (matrix != null) { 271 matrix.removeTableModelListener(this); 272 } 273 ToolTipManager.sharedInstance().unregisterComponent(this); 274 } 275 276 protected void paintComponent(Graphics g) { 277 super.paintComponent(g); 278 Graphics2D g2d = (Graphics2D) g; 279 280 if (matrix != null && bufferedImage != null) { 281 g2d.drawImage(bufferedImage, 0, 0, getWidth(), getHeight(), null); 282 283 if (!matrix.getRowSelectionModel().isSelectionEmpty()) { 284 g2d.setColor(Color.BLUE); 285 286 int x1 = matrix.getColumnSelectionModel() 287 .getMinSelectionIndex(); 288 int x2 = matrix.getColumnSelectionModel() 289 .getMaxSelectionIndex(); 290 int y1 = matrix.getRowSelectionModel().getMinSelectionIndex(); 291 int y2 = matrix.getRowSelectionModel().getMaxSelectionIndex(); 292 double sx = (double) (getWidth() - PADDINGX - PADDINGX) 293 / (double) matrix.getColumnCount(); 294 double sy = (double) (getHeight() - PADDINGY - PADDINGY) 295 / (double) matrix.getRowCount(); 296 g2d.setStroke(new BasicStroke(2.0f)); 297 g2d 298 .drawRect((int) Math.floor(PADDINGX + x1 * sx), 299 (int) Math.floor(PADDINGY + y1 * sy), 300 (int) Math.ceil(sx + (x2 - x1) * sx), 301 (int) Math.ceil(sy + (y2 - y1) * sy)); 302 g2d.setComposite(AlphaComposite.getInstance( 303 AlphaComposite.SRC_ATOP, 0.3f)); 304 g2d 305 .fillRect((int) Math.floor(PADDINGX + x1 * sx), 306 (int) Math.floor(PADDINGY + y1 * sy), 307 (int) Math.ceil(sx + (x2 - x1) * sx), 308 (int) Math.ceil(sy + (y2 - y1) * sy)); 309 } 310 } else { 311 g2d.setColor(Color.GRAY); 312 g2d.drawLine(0, 0, getWidth(), getHeight()); 313 g2d.drawLine(0, getHeight(), getWidth(), 0); 314 } 315 } 316 317 public void repaintUI() { 318 if (matrix != null && getWidth() > 0 && getHeight() > 0) { 319 BufferedImage tempBufferedImage = new BufferedImage(getWidth(), 320 getHeight(), BufferedImage.TYPE_INT_RGB); 321 renderer.setSize(getWidth(), getHeight()); 322 Graphics2D g2d = (Graphics2D) tempBufferedImage.getGraphics(); 323 renderer.paintComponent(g2d); 324 g2d.dispose(); 325 bufferedImage = tempBufferedImage; 326 } 327 } 328 329 public void exportToPDF(File file) { 330 ExportPDF.save(file, this); 331 } 332 333 public void exportToJPEG(File file) { 334 ExportJPEG.save(file, this); 335 } 336 337 public void exportToPNG(File file) { 338 ExportPNG.save(file, this); 339 } 340 341 public void mouseDragged(MouseEvent e) { 342 if (matrix != null) { 343 if (matrix.getRowSelectionModel().getValueIsAdjusting()) { 344 int newRow = getRowPos(e.getY()); 345 int newCol = getColPos(e.getX()); 346 newRow = newRow < 0 ? 0 : newRow; 347 newCol = newCol < 0 ? 0 : newCol; 348 newRow = newRow >= matrix.getRowCount() ? matrix.getRowCount() - 1 349 : newRow; 350 newCol = newCol >= matrix.getColumnCount() ? matrix 351 .getColumnCount() - 1 : newCol; 352 matrix.getRowSelectionModel().setSelectionInterval(startRow, 353 newRow); 354 matrix.getColumnSelectionModel().setSelectionInterval(startCol, 355 newCol); 356 repaint(100); 357 } 358 } 359 } 360 361 public void mouseMoved(MouseEvent e) { 362 } 363 364 public void valueChanged(ListSelectionEvent e) { 365 repaint(100); 366 } 367 }