1 package org.nightlabs.editor2d.viewer; 2 3 import java.awt.Color ; 4 import java.awt.Graphics ; 5 import java.awt.Graphics2D ; 6 import java.awt.Rectangle ; 7 import java.awt.geom.Point2D ; 8 import java.awt.image.BufferedImage ; 9 import java.beans.PropertyChangeListener ; 10 import java.beans.PropertyChangeSupport ; 11 import java.util.Iterator ; 12 13 import javax.swing.JPanel ; 14 15 import org.apache.log4j.Logger; 16 import org.nightlabs.base.util.GeomUtil; 17 import org.nightlabs.editor2d.DrawComponent; 18 import org.nightlabs.editor2d.render.Renderer; 19 20 public abstract class AbstractBufferedCanvas 21 extends JPanel 22 implements IBufferedCanvas, IViewport 23 { 24 public static final Logger LOGGER = Logger.getLogger(AbstractBufferedCanvas.class); 25 26 protected ITempContentManager tempContentManager = null; 27 public ITempContentManager getTempContentManager() 28 { 29 if (tempContentManager == null) 30 tempContentManager = new TempContentManager(); 31 32 return tempContentManager; 33 } 34 35 protected PropertyChangeSupport pcs = null; 36 protected PropertyChangeSupport getPropertyChangeSupport() 37 { 38 if (pcs == null) { 39 pcs = new PropertyChangeSupport (this); 40 } 41 return pcs; 42 } 43 44 public void addPropertyChangeListener(PropertyChangeListener pcl) { 45 getPropertyChangeSupport().addPropertyChangeListener(pcl); 46 } 47 48 public void removePropertyChangeListener(PropertyChangeListener pcl) { 49 getPropertyChangeSupport().removePropertyChangeListener(pcl); 50 } 51 52 public void firePropertyChange(String propertyName, Object newVal, Object oldVal) { 53 getPropertyChangeSupport().firePropertyChange(propertyName, oldVal, newVal); 54 } 55 56 public AbstractBufferedCanvas(DrawComponent dc) 57 { 58 super(); 59 this.dc = dc; 60 Rectangle dcBounds = GeomUtil.translateRectToOrigin(dc.getBounds()); 61 renderingHintsManager.setRenderMode(RenderingHintsManager.RENDER_MODE_QUALITY); 63 init(dcBounds); 64 } 66 67 public DrawComponent getDrawComponent() { 68 return dc; 69 } 70 71 private boolean debugBounds = false; 72 private boolean debugPaint = false; 73 74 private void setDebug(boolean paint, boolean bounds) 75 { 76 debugPaint = paint; 77 debugBounds = bounds; 78 } 79 80 protected int imageType = BufferedImage.TYPE_INT_RGB; 81 protected Rectangle bufferBounds; 82 protected DrawComponent dc; 83 protected BufferedImage bufferedImage; 84 protected BufferedImage viewImage; 85 protected int initSize = 100; 86 protected RenderingHintsManager renderingHintsManager = RenderingHintsManager.sharedInstance(); 87 88 92 public void paint(Graphics g) 93 { 94 Graphics2D g2d = (Graphics2D ) g; 95 96 long startPaintTime = 0; 97 if (debugPaint) { 98 startPaintTime = System.currentTimeMillis(); 99 } 100 101 if (isChanged) 102 { 103 if (debugPaint) 104 LOGGER.debug("buffer cleared!"); 105 106 paintDrawComponent(); 107 isChanged = false; 108 } 109 110 g2d.setPaint(bgColor); 112 Rectangle bgRect = initRealBounds; 113 g2d.setClip(0, 0, bgRect.width, bgRect.height); 114 g2d.fillRect(0, 0, bgRect.width, bgRect.height); 115 116 if (debugBounds) 117 LOGGER.debug("bgRect = "+bgRect); 118 119 if (bufferedImage != null) 120 { 121 long startTime = 0; 122 if (debugPaint) 123 startTime = System.currentTimeMillis(); 124 125 calcBufferedViewImage(); 127 g2d.drawImage(viewImage, 0, 0, null); 128 129 if (debugPaint) 130 LOGGER.debug("BitBlockTransfer took "+(System.currentTimeMillis()-startTime)+" ms!"); 131 132 if (debugBounds) { 133 LOGGER.debug("viewImage width = "+viewImage.getWidth()); 134 LOGGER.debug("viewImage height = "+viewImage.getHeight()); 135 } 136 } 137 138 if (drawTempContent == true) { 140 g2d.translate(-getOffsetX(), -getOffsetY()); 141 g2d.scale(getScale(), getScale()); 142 drawTempContent(g2d); 143 } 144 145 if (debugPaint) { 146 LOGGER.debug("Total Paint took "+(System.currentTimeMillis()-startPaintTime)+" ms"); 147 LOGGER.debug(""); 148 } 149 } 150 151 156 protected void calcBufferedViewImage() 157 { 158 int offsetX = getBufferOffsetX(); 159 int offsetY = getBufferOffsetY(); 160 161 if (viewImage != null) 162 viewImage.flush(); 163 164 long startTime = 0; 165 if (debugPaint) { 166 startTime = System.currentTimeMillis(); 167 } 168 169 if ((bufferedImage.getWidth() >= viewBounds.width + offsetX) && 170 (bufferedImage.getHeight() >= viewBounds.height + offsetY)) 171 { 172 viewImage = 173 bufferedImage.getSubimage(offsetX, offsetY, 174 viewBounds.width, 175 viewBounds.height); 176 } 177 178 if (debugPaint) { 179 long endTime = System.currentTimeMillis() - startTime; 180 LOGGER.debug("create viewImage took "+endTime+" ms!"); 181 } 182 } 183 184 190 protected void setZoomedRealBounds(double scale) 191 { 192 int newWidth = (int) Math.floor(initRealBounds.width * scale); 193 int newHeight = (int) Math.floor(initRealBounds.height * scale); 194 Rectangle newRealBounds = new Rectangle (0, 0, newWidth, newHeight); 195 setRealBounds(newRealBounds); 196 } 197 198 protected double scale = 1.0d; 199 protected double oldScale = scale; 200 201 205 public void setScale(double scale) { 206 oldScale = this.scale; 207 this.scale = scale; 208 setZoomedRealBounds(scale); 209 } 210 211 214 public double getScale() { 215 return scale; 216 } 217 218 221 public void translateX(float translateX) { 222 setViewLocation((int)(viewBounds.x + translateX), viewBounds.y); 223 } 224 225 228 public void translateY(float translateY) { 229 setViewLocation(viewBounds.x, (int)(viewBounds.y + translateY)); 230 } 231 232 protected Color bgColor = Color.WHITE; 233 public void setBackground(int red, int green, int blue, int alpha) { 234 bgColor = new Color (red, green, blue, alpha); 235 } 236 237 protected Rectangle realBounds; 238 239 244 public Rectangle getRealBounds() { 245 return realBounds; 246 } 247 public void setRealBounds(Rectangle realBounds) 248 { 249 Rectangle oldReal = this.realBounds; 250 checkScale(realBounds); 251 scaleToCenter(); 252 firePropertyChange(REAL_CHANGE, oldReal, this.realBounds); 253 setViewBounds(getViewBounds()); 254 notifyChange(); 255 } 256 257 262 protected void scaleToCenter() 263 { 264 int newViewX = (int) ((((double)viewBounds.x) / oldScale) * scale); 265 int newViewY = (int) ((((double)viewBounds.y) / oldScale) * scale); 266 269 if (debugBounds) { 270 LOGGER.debug("newViewX = "+newViewX); 271 LOGGER.debug("newViewY = "+newViewY); 272 } 273 274 setViewLocation(newViewX, newViewY); 275 } 276 277 protected Rectangle viewBounds; 278 279 283 public Rectangle getViewBounds() { 284 return viewBounds; 285 } 286 287 290 public Point2D getViewLocation() 291 { 292 return getViewBounds().getLocation(); 293 } 294 295 299 public void setViewBounds(Rectangle viewBounds) 300 { 301 Rectangle oldView = this.viewBounds; 302 303 if (isRectangleInReal(viewBounds)) 304 this.viewBounds = viewBounds; 305 else 306 this.viewBounds = GeomUtil.checkBounds(viewBounds, realBounds); 307 308 firePropertyChange(VIEW_CHANGE, oldView, this.viewBounds); 309 checkBuffer(); 310 repaint(); 311 312 if (debugBounds) { 313 LOGGER.debug("realBounds = " + realBounds); 314 LOGGER.debug("bufferBounds = " + bufferBounds); 315 LOGGER.debug("viewBounds = "+viewBounds); 316 LOGGER.debug(""); 317 } 318 } 319 320 protected Rectangle initRealBounds; 321 protected Rectangle initViewBounds; 322 323 protected void init(Rectangle realBounds) 324 { 325 initRealBounds = new Rectangle (realBounds); 326 initViewBounds = getVisibleRect(); 327 328 this.realBounds = realBounds; 329 viewBounds = getVisibleRect(); 330 initBuffer(); 331 paintDrawComponent(); 332 334 if (debugBounds) { 335 LOGGER.debug("realBounds = "+realBounds); 336 LOGGER.debug("viewBounds = "+viewBounds); 337 } 338 } 339 340 protected void initBuffer() 341 { 342 bufferBounds = new Rectangle (0, 0, initSize, initSize); 343 bufferedImage = new BufferedImage (bufferBounds.width, bufferBounds.height, imageType); 344 } 345 346 protected boolean isChanged = false; 347 348 352 public void notifyChange() 353 { 354 isChanged = true; 355 repaint(); 356 357 LOGGER.debug("notifyChange!"); 358 } 359 360 363 protected void paintDrawComponent() 364 { 365 long startTime = 0; 366 if (debugPaint) 367 startTime = System.currentTimeMillis(); 368 369 if (bufferedImage != null) 370 { 371 Graphics2D g2d = (Graphics2D ) bufferedImage.getGraphics(); 372 g2d.setRenderingHints(renderingHintsManager.getRenderingHints()); 373 g2d.setBackground(bgColor); 374 g2d.translate(-bufferBounds.x, -bufferBounds.y); 375 376 g2d.setClip(bufferBounds); 377 g2d.fillRect(bufferBounds.x, bufferBounds.y, bufferBounds.width, bufferBounds.height); 378 379 g2d.scale(scale, scale); 380 DrawComponentPaintable.paintDrawComponent(dc, g2d); 381 } 382 383 if (debugPaint) 384 { 385 long endTime = System.currentTimeMillis() - startTime; 386 LOGGER.debug("paintDrawComponent took "+endTime+" ms!"); 387 } 388 } 389 390 395 protected Rectangle getBufferRectangle() 396 { 397 double bufferScaleFactor = BufferManager.sharedInstance().getBufferScaleFactor(); 398 int bufferWidth = (int) (viewBounds.width * bufferScaleFactor); 399 int bufferHeight = (int) (viewBounds.height * bufferScaleFactor); 400 401 Rectangle newBufferBounds = new Rectangle (viewBounds.x - ((bufferWidth - viewBounds.width)/2), 402 viewBounds.y - ((bufferHeight-viewBounds.height)/2), bufferWidth, bufferHeight); 403 404 if (isRectangleInReal(newBufferBounds)) 405 return newBufferBounds; 406 else 407 return GeomUtil.checkBounds(newBufferBounds, realBounds); 408 } 409 410 416 protected void checkBuffer() 417 { 418 if (!isViewInBuffer()) 419 { 420 if (bufferedImage != null) 421 bufferedImage.flush(); 422 bufferedImage = null; 423 createOffScreenImage(); 424 notifyChange(); 425 426 if (debugBounds) 427 LOGGER.debug("Buffer updated!"); 428 } 429 } 430 431 435 protected boolean isViewInBuffer() 436 { 437 if (bufferBounds != null && viewBounds != null) 438 return bufferBounds.contains(viewBounds); 439 else 440 return false; 441 } 442 443 448 protected boolean isRectangleInReal(Rectangle r) 449 { 450 if (realBounds != null && r != null) 451 return realBounds.contains(r); 452 else 453 return false; 454 } 455 456 461 protected void createOffScreenImage() 462 { 463 bufferBounds = getBufferRectangle(); 464 bufferedImage = new BufferedImage (bufferBounds.width, bufferBounds.height, imageType); 465 } 466 467 public int getOffsetX() { 468 return viewBounds.x - realBounds.x; 469 } 470 471 public int getOffsetY() { 472 return viewBounds.y - realBounds.y; 473 } 474 475 protected int getBufferOffsetX() { 476 return viewBounds.x - bufferBounds.x; 477 } 478 479 protected int getBufferOffsetY() { 480 return viewBounds.y - bufferBounds.y; 481 } 482 483 public void setViewLocation(int x, int y) { 484 setViewBounds(new Rectangle (x, y, viewBounds.width, viewBounds.height)); 485 } 486 487 public void setViewLocation(Point2D p) { 488 setViewLocation((int)p.getX(), (int)p.getY()); 489 } 490 491 public void setViewCenter(float x, float y) 492 { 493 Rectangle newView = new Rectangle (); 494 newView.setFrameFromCenter(x, y, 495 x + viewBounds.getWidth() / 2, 496 y + viewBounds.getHeight() / 2); 497 setViewBounds(newView); 498 } 499 500 public Point2D getViewCenter() 501 { 502 double viewCenterX = viewBounds.getCenterX(); 503 double viewCenterY = viewBounds.getCenterY(); 504 return new Point2D.Float ((float)viewCenterX, (float)viewCenterY); 505 } 506 507 protected void checkScale(Rectangle newReal) 508 { 509 int maxRealX = (int)newReal.getMaxX(); 510 int maxRealY = (int)newReal.getMaxY(); 511 int maxViewX = (int)initViewBounds.getMaxX(); 512 int maxViewY = (int)initViewBounds.getMaxY(); 513 int maxX = Math.max(maxRealX, maxViewX); 514 int maxY = Math.max(maxRealY, maxViewY); 515 realBounds = new Rectangle (0, 0, maxX, maxY); 516 517 if (debugBounds) { 518 LOGGER.debug("viewBounds = "+viewBounds); 519 LOGGER.debug("realBounds = "+realBounds); 520 LOGGER.debug("initViewBounds = "+initViewBounds); 521 } 522 } 523 524 protected boolean drawTempContent = true; 525 public void drawTempContent(Graphics2D g2d) 526 { 527 for (Iterator it = getTempContentManager().getTempContent().iterator(); it.hasNext(); ) 528 { 529 Object o = it.next(); 530 if (o instanceof DrawComponent) { 531 DrawComponent dc = (DrawComponent) o; 532 Renderer r = null; 533 if (dc.getRoot() != null) { 534 r = dc.getRenderer(); 535 } 536 if (r == null) { 537 int renderMode = dc.getRenderMode(); 538 r = getDrawComponent().getRenderModeManager().getRenderer(renderMode, dc.getClass()); 539 } 540 r.paint(dc, g2d); 541 } 542 } 543 } 544 545 public abstract Rectangle getVisibleRect(); 546 547 protected void componentResized() 548 { 549 Rectangle visibleRect = getVisibleRect(); 550 initViewBounds = getVisibleRect(); 551 Rectangle newView = new Rectangle (viewBounds.x, viewBounds.y, 552 visibleRect.width, visibleRect.height); 553 554 if (!newView.equals(viewBounds)) 555 { 556 setViewBounds(newView); 557 if (debugBounds) { 558 LOGGER.debug("Viewport resized!"); 559 LOGGER.debug("viewBounds = "+viewBounds); 560 } 561 } 562 } 563 564 } 565 | Popular Tags |